fix: seven small honesty fixes from the 29.08 audit (#369)

(a) documented: deleting a vacuum marker erases its server trail at once
and a re-added marker starts from scratch (VACUUM.md + both USER-GUIDEs).
(b) smoothVacPath reports dropped non-finite segments — one console warn
per call with the count — instead of hiding the whole trail silently on a
broken calibration matrix. (c) room climate (#317) now reaches legacy
markers whose exported config carries an ABSENT area key rather than an
explicit null: `== null` where the placement is decided. (d) the armed
furniture preview follows Shift without mouse movement — window
keydown/keyup listeners live exactly as long as the palette is armed,
detached at every palette teardown. (e) only the primary mouse button
places decor/furniture: a right or middle click with an armed tool is a
no-op, touch/pen untouched. (f) a device whose registry entities were ALL
deliberately disabled by the user no longer glows as an alive controller —
the #318 entityless-active rule now requires a genuinely empty roster.
(g) furniture-pack author corrected to Sergey Matyunin (Сергей Матюнин)
per the owner's decision — LICENSE.md, README.md, pack.json,
docs/FURNITURE.md, the provenance check in generate-furniture-assets and
its unit; the source archive bytes are unchanged and the README notes the
romanisation fix.

Proofs: units for (b)/(c)/(f) including the #318 regression pair; new
smoke_furniture_polish for (d)/(e) with listener add/remove counters and
both mouse buttons; five registry mutants, one per code change.

Issue: #369
User-Visible: yes
This commit is contained in:
Codex
2026-08-29 11:29:42 +03:00
parent a041934bc2
commit 8ee1c91fff
38 changed files with 551 additions and 212 deletions
+60
View File
@@ -692,6 +692,66 @@ const MUTANT_DEFINITIONS = [
replace: ' return safe;',
}],
},
{
id: 'vac-trail-drop-warn-removed',
guard: 'node --test --test-name-pattern="#369" test/vacuum.test.mjs',
because: 'a NaN calibration must not hide the trail silently — the drop count belongs in the '
+ 'console (#369b)',
patches: [{
file: 'src/vacuum.ts',
find: ' if (droppedSegments > 0) {\n'
+ ' warn(`[houseplan] vacuum trail: ${droppedSegments} segment(s) dropped — non-finite point (check map calibration)`);\n'
+ ' }',
replace: ' void droppedSegments; void warn;',
}],
},
{
id: 'climate-legacy-area-undefined-lost',
guard: 'node --test --test-name-pattern="369в" test/devices.test.mjs',
because: 'legacy/import markers carry an absent area key, not an explicit null — strict '
+ 'equality quietly demotes their climate back to the registry fallback (#369v)',
patches: [{
file: 'src/devices.ts',
find: ' if (marker.area == null && marker.space && marker.room_id) {',
replace: ' if (marker.area === null && marker.space && marker.room_id) {',
}],
},
{
id: 'opted-out-roster-looks-alive',
guard: 'node --test --test-name-pattern="369г" test/device-presentation.test.mjs',
because: 'a roster the user deliberately disabled is evidence of opting out, not of life — '
+ 'dropping the guard makes the marker glow forever (#369g)',
patches: [{
file: 'src/device-presentation.ts',
find: ' const activeEntitylessDevice = ownEntities.length === 0\n'
+ ' && !disabledRoster\n',
replace: ' void disabledRoster;\n'
+ ' const activeEntitylessDevice = ownEntities.length === 0\n',
}],
},
{
id: 'furniture-shift-listeners-not-attached',
guard: 'node demo/smoke_furniture_polish.mjs',
because: 'without the window listeners the preview ignores Shift until the mouse moves — the '
+ 'exact drift the smoke pins (#369d)',
patches: [{
file: 'src/houseplan-editor-runtime.ts',
find: ' this.host._furnPalette = { symbol, w: d.w, h: d.h };\n'
+ ' this._furnShiftAttach();',
replace: ' this.host._furnPalette = { symbol, w: d.w, h: d.h };',
}],
},
{
id: 'placement-accepts-any-mouse-button',
guard: 'node demo/smoke_furniture_polish.mjs',
because: 'a right click with an armed tool must not stamp furniture (#369e)',
patches: [{
file: 'src/houseplan-editor-runtime.ts',
find: " if (ev.pointerType === 'mouse' && ev.button !== 0\n"
+ " && t !== 'select' && t !== 'erase') return false;",
replace: ' // mutant: any button places',
}],
},
{
id: 'backdrop-probe-always-safe',
guard: 'node demo/smoke_backdrop_guard.mjs',