mirror of
https://github.com/Matysh/houseplan-card
synced 2026-10-01 12:18:51 +00:00
feat: junction limits refuse the write in every editing surface (#329)
П3 measures the WALL, not the catalogue atom: a short filler segment that compensates a thickness step (owner's fixture, 5 cm = (30-20)/2) is a legal continuation of a long same-thickness wall, so the rule walks the maximal collinear run through the shared nodes before judging the length. Resize stops at the last allowed position and names the broken rule instead of the generic "geometry cannot be saved"; the Thickness dialog refuses through its own toast. Both channels are pinned by demo/smoke_junction_limits plus three mutants (angle threshold, write barrier, degenerate apex bevel). Issue: #329 User-Visible: yes
This commit is contained in:
@@ -537,6 +537,43 @@ export const MUTANTS = [
|
||||
replace: ' // mutant: pointer capture removed\n const plan = resolution.plan;',
|
||||
}],
|
||||
},
|
||||
{
|
||||
id: 'junction-limit-angle-not-enforced',
|
||||
guard: 'npx tsc -p tsconfig.test.json && node scripts/fix-test-build.mjs '
|
||||
+ '&& node --test --test-name-pattern="П1" test/junction-limits.test.mjs',
|
||||
because: 'the owner-approved 15° minimum between neighbouring walls is a hard limit; '
|
||||
+ 'lowering it silently lets the trident apex of #329 be drawn again',
|
||||
patches: [{
|
||||
file: 'src/junction-limits.ts',
|
||||
find: 'export const MIN_JUNCTION_ANGLE_DEG = 15;',
|
||||
replace: 'export const MIN_JUNCTION_ANGLE_DEG = 0;',
|
||||
}],
|
||||
},
|
||||
{
|
||||
id: 'junction-limit-write-gate-removed',
|
||||
guard: 'node demo/smoke_junction_limits.mjs',
|
||||
because: 'the limits must refuse the WRITE, not merely report it — without the barrier '
|
||||
+ 'an impossible junction reaches the saved document (#329 §2)',
|
||||
patches: [{
|
||||
file: 'src/houseplan-card.ts',
|
||||
find: ' if (introduced.length) {\n this._clearGeometryGesture();',
|
||||
replace: ' if (false && introduced.length) {\n this._clearGeometryGesture();',
|
||||
}],
|
||||
},
|
||||
{
|
||||
id: 'degenerate-apex-bevelled-again',
|
||||
guard: 'npx tsc -p tsconfig.test.json && node scripts/fix-test-build.mjs '
|
||||
+ '&& node --test --test-name-pattern="§4" test/junction-limits.test.mjs',
|
||||
because: 'a sharp apex must end in ONE point on both faces; the two-point bevel is the '
|
||||
+ 'flat cut the owner rejected and the bow-tie fold that carved the jags (#329 §4)',
|
||||
patches: [{
|
||||
file: 'src/wall-thickness.ts',
|
||||
find: ' if (isDegenerateApexCorner(poly, offsets, i)) {\n'
|
||||
+ ' out.push([poly[i][0], poly[i][1]]);\n'
|
||||
+ ' continue;\n }',
|
||||
replace: ' // mutant: degenerate apex falls back to the bevel',
|
||||
}],
|
||||
},
|
||||
{
|
||||
id: 'resize-preview-reject-silent',
|
||||
guard: 'node demo/smoke_room_resize.mjs',
|
||||
@@ -544,7 +581,12 @@ export const MUTANTS = [
|
||||
+ 'stopped instead of restoring the original silent no-op (#293)',
|
||||
patches: [{
|
||||
file: 'src/houseplan-card.ts',
|
||||
find: " this._showToast(this._t('resize.preview_failed'));",
|
||||
find: [
|
||||
' this._showToast(this._rszLimitViolation',
|
||||
' ? `${this._t(\'resize.limit_stopped\')} — `',
|
||||
' + this._junctionLimitLabel(this._rszLimitViolation)',
|
||||
" : this._t('resize.preview_failed'));",
|
||||
].join('\n'),
|
||||
replace: ' // mutant: reject remains silent',
|
||||
}],
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user