test: grade the wall-key invariant by what the product does
Validate / docs (push) Failing after 25s
Validate / process-workflow-sync (push) Successful in 1m13s
Validate / provenance (push) Failing after 1m16s
Validate / process-gate (push) Failing after 1m25s
Validate / changes (push) Successful in 1m9s
Validate / reuse (push) Successful in 58s
Validate / hacs (push) Failing after 17s
Validate / hassfest (push) Failing after 20s
Validate / frontend (push) Successful in 10m20s
Validate / backend (push) Failing after 9m54s
Validate / smoke (1) (push) Failing after 18m2s
Validate / smoke (2) (push) Failing after 17m49s
Validate / smoke (3) (push) Failing after 15m44s
Validate / smoke_done (push) Skipped
Validate / golden (push) Failing after 15m1s
Validate / performance_smoke (push) Failing after 13m49s

The first cut of checkWallKeys compared the stored key against endpoints
snapped to the lattice and called any mismatch a violation. Both halves were
wrong, and measurement says so: wallIntervals reports the query key for the
disputed edge as 0.887500,0.195833@1.5706, i.e. the form built from the
coordinates as stored, and the two owner configurations that differ in exactly
these keys produce byte-identical wall bodies and multi-wall node maps. The
check would have reddened a plan that renders correctly.

Graded now: a drift inside the tolerant fallback's half-pitch reach is an
observation, a key beyond it or one that does not parse as coordinates is a
violation. The threshold is expressed in grid steps with a 1e-3 slack — with a
relative 1e-6 the four identically drifted records of one plan split between
the two classes on their last bits, so the check repeated the very rounding tie
it exists to expose.

visual-matrix leaves KEY_CONTRACT_DEBT: its keys drift inside the reach and now
read as observations. large-house stays — its labels do not parse, and
wallIntervals shows all 80 solid edges resolving to zero thickness (#260).

Issue: #259
User-Visible: no
This commit is contained in:
Claude
2026-08-23 14:11:22 +03:00
parent 2970b8091b
commit 5e95a28406
4 changed files with 217 additions and 117 deletions
+24 -12
View File
@@ -231,27 +231,39 @@ export const MUTANTS = [
}],
},
{
id: 'invariant-keys-from-raw-endpoints',
guard: 'node --test --test-name-pattern="ключ, пересчитанный от сырых концов" '
id: 'invariant-keys-cry-wolf',
guard: 'node --test --test-name-pattern="ушедший на шаг решётки" '
+ 'test/model-invariants.test.mjs',
because: 'ключ считается от концов НА РЕШЁТКЕ, а не от сырых: от сырых проверка '
+ 'помечает исправное состояние и пропускает дефектное — ровно этой ошибкой была '
+ 'первая формулировка в #258',
because: 'запись, ушедшую на полшага, продукт НАХОДИТ — измерено на двух конфигах '
+ 'владельца с побайтово одинаковыми телами стен; объявить это нарушением значит '
+ 'покрасить исправный план, а такую проверку отключают первой (#258)',
patches: [{
file: 'scripts/model-invariants.mjs',
find: ' const expected = wallKey(latticePoint(a), latticePoint(b));',
replace: ' const expected = wallKey(a, b);',
find: ' if (steps > 0.5 + 1e-3) {',
replace: ' if (steps > 0) {',
}],
},
{
id: 'invariant-keys-tolerate-one-step',
guard: 'node --test --test-name-pattern="детектор ключей умеет падать" '
id: 'invariant-keys-tolerate-any-drift',
guard: 'node --test --test-name-pattern="дальше терпимого запаса" '
+ 'test/model-invariants.test.mjs',
because: 'смысл проверки — сравнение строк без допусков: допуск здесь и был причиной '
+ 'промаха, потому что сдвиг ключа на шаг решётки равен допуску checkReferences',
because: 'ключ, ушедший дальше полшага, не находит ни точное совпадение, ни запас — '
+ 'если проверка это пропустит, запись толщины молча перестанет существовать',
patches: [{
file: 'scripts/model-invariants.mjs',
find: ' if (wall.key !== expected) {',
find: ' if (steps > 0.5 + 1e-3) {',
replace: ' if (false) {',
}],
},
{
id: 'invariant-keys-accept-a-label',
guard: 'node --test --test-name-pattern="не разбирается как координаты" '
+ 'test/model-invariants.test.mjs',
because: 'метка вместо ключа (perf-wall-0-3 в перф-фикстуре, #260) оставляет все 80 '
+ 'сплошных рёбер без толщины: проверка обязана отличать её от сдвига на полшага',
patches: [{
file: 'scripts/model-invariants.mjs',
find: ' if (!stored) {',
replace: ' if (false) {',
}],
},