mirror of
https://github.com/Matysh/houseplan-card
synced 2026-09-29 03:09:36 +00:00
feat: junction nodes — detector, fans over the approved chamfer, scene set (#302)
Вторая половина переработки узлов поверх ядра из прошлого коммита: - `junctionContractHoles` — объективный инвариант «тело ⊇ полосы ∪ веера в фасадной границе» как экспортная чистая функция; самопроверка на заведомо дырявой фикстуре входит в юниты. Первая формулировка детектора из ТЗ («окружено кладкой с ≥5 из 8 сторон») уточнена в §8.4 по факту измерения: она ложно флагует легитимный пол комнаты в острых внутренних углах. - `junctionNodeBound` — «гладкая» фасадная граница (конверт с обычными углами) экспортирована: ею клиппуются куски узла и ею же пользуются тесты. - юниты #302: веера/рефлекс/короткий толстый саппорт/детектор/репро end-to-end; хелпер тестов старого контракта переведён на strip-safe семантику по саппортам и фасадной границе. - смок `smoke_junction_holes`: контрактные пробы считаются в node из той же фикстуры и проверяются в браузере по реальному `d`-пути карточки. - сет из 16 golden-сцен стыков крупным планом (звёзды лучей: T/X/Y/острые/ почти коллинеарные/виртуальные/колонна/черновик) + сцена-репро владельца; билдер сцен и `zoomCenter` в harness. Контракт сцены `multiwall-junction-bevel-view-dark` инвертирован по решению владельца: проба в перекрытии полос обязана быть ЗАПОЛНЕНА (strip-safe), а не пустой. - семь мутантов §14, включая слепоту детектора и невозврат саппортов. - фикстура #197: площадь кладки выросла на 0.2 юнита² — слайвер вееров вдоль хорд фаски; константа обновлена с комментарием. Эталоны новых сцен идут отдельным коммитом с положенными трейлерами. Issue: #302 User-Visible: yes
This commit is contained in:
@@ -2209,6 +2209,77 @@ export const MUTANTS = [
|
||||
replace: ' .dev:not(.unavail):hover {',
|
||||
}],
|
||||
},
|
||||
{
|
||||
id: 'junction-fans-disabled',
|
||||
guard: 'npx tsc -p tsconfig.test.json && node scripts/fix-test-build.mjs && node --test --test-name-pattern="issue 302" test/wall-thickness.test.mjs',
|
||||
because: 'без вееров сектор между соседними полосами узла остаётся дырой — '
|
||||
+ 'это и есть класс артефактов #302',
|
||||
patches: [{
|
||||
file: 'src/wall-thickness.ts',
|
||||
find: ' if (mitre && mitreWithinStrips',
|
||||
replace: ' if (false && mitre && mitreWithinStrips',
|
||||
}, {
|
||||
file: 'src/wall-thickness.ts',
|
||||
find: ' push(out.fans, [[P[0], P[1]], EA, A2, B2, EB]);',
|
||||
replace: ' void A2; void B2;',
|
||||
}],
|
||||
},
|
||||
{
|
||||
id: 'junction-supports-not-restored',
|
||||
guard: 'npx tsc -p tsconfig.test.json && node scripts/fix-test-build.mjs && node --test --test-name-pattern="hole-free end to end" test/wall-thickness.test.mjs',
|
||||
because: 'фаска старого слоя срезает материал полос на острых стыках; '
|
||||
+ 'без возврата саппорт-квадов узла репро владельца снова дырявое',
|
||||
patches: [{
|
||||
file: 'src/wall-thickness.ts',
|
||||
find: ' for (const piece of [...corners.supports, ...corners.fans]) {',
|
||||
replace: ' for (const piece of corners.fans) {',
|
||||
}],
|
||||
},
|
||||
{
|
||||
id: 'junction-fan-ignores-thick-length',
|
||||
guard: 'npx tsc -p tsconfig.test.json && node scripts/fix-test-build.mjs && node --test --test-name-pattern="issue 302" test/wall-thickness.test.mjs',
|
||||
because: 'веер, шагающий за короткий толстый саппорт, рисует латеральный '
|
||||
+ 'фантом рядом с тонким продолжением (#271)',
|
||||
patches: [{
|
||||
file: 'src/wall-thickness.ts',
|
||||
find: ' mitreWithinStrips = tA <= A.thickLength && tB <= B.thickLength;',
|
||||
replace: ' mitreWithinStrips = true;',
|
||||
}],
|
||||
},
|
||||
{
|
||||
id: 'junction-reflex-sector-fanned',
|
||||
guard: 'npx tsc -p tsconfig.test.json && node scripts/fix-test-build.mjs && node --test --test-name-pattern="issue 302" test/wall-thickness.test.mjs',
|
||||
because: 'рефлексный сектор — внешность выпуклого угла; веер там — лишний '
|
||||
+ 'фасадный материал (контракт вогнутого Split)',
|
||||
patches: [{
|
||||
file: 'src/wall-thickness.ts',
|
||||
find: ' if (sector > Math.PI + 1e-9) continue;',
|
||||
replace: ' void sector;',
|
||||
}],
|
||||
},
|
||||
{
|
||||
id: 'junction-detector-blind',
|
||||
guard: 'npx tsc -p tsconfig.test.json && node scripts/fix-test-build.mjs && node --test --test-name-pattern="issue 302" test/wall-thickness.test.mjs',
|
||||
because: 'слепой детектор превращает инвариант «нет дыр» в декорацию — '
|
||||
+ 'самопроверка на заведомо дырявой фикстуре обязана краснеть',
|
||||
patches: [{
|
||||
file: 'src/wall-thickness.ts',
|
||||
find: ' if (!inGeometry(geometry, x, y)) holes.push([x, y]);',
|
||||
replace: ' void x; void y;',
|
||||
}],
|
||||
},
|
||||
{
|
||||
id: 'junction-pieces-unbounded',
|
||||
guard: 'npx tsc -p tsconfig.test.json && node scripts/fix-test-build.mjs '
|
||||
+ '&& node --test --test-name-pattern="concave vertex" test/wall-thickness.test.mjs',
|
||||
because: 'куски узла без клипа гладкой фасадной границей отращивают новый '
|
||||
+ 'фасад на вогнутой вершине',
|
||||
patches: [{
|
||||
file: 'src/wall-thickness.ts',
|
||||
find: ' if (bound) ring = intersection(ring, bound);',
|
||||
replace: ' void bound;',
|
||||
}],
|
||||
},
|
||||
{
|
||||
id: 'hatch-step-ignores-cell-cm',
|
||||
guard: 'npx tsc -p tsconfig.test.json && node scripts/fix-test-build.mjs '
|
||||
|
||||
Reference in New Issue
Block a user