You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Follow-up to #2154. This is the measurement, not a corpus rewrite. No spec under specs/ is modified by any tool added here.
Frozen before touching anything
docs/corpus/damage_snapshot_2026-08-15.json — 125 lines, 65 files, 15 shapes, corpus_sha256 = 1b5a37b7a89efb782db7efd2ca7af728d4ed48b1c13ac2a35088c7926b16afd9. Per row: class id, shape, file, line, field, verbatim rhs, 2 lines of context either side, and the file digest. tri damage-repair REFUSES to run if any digest has moved since the freeze.
Class ids are DC- + 8 hex of sha256(shape), deliberately not a frequency rank, so adding a class later does not renumber a citation.
The mechanism, established from the corpus
An intact field is name : "TypeText",. Every damaged line has one defect: the opening quote of the type string was replaced by [.
intact children : "[4]?QuadNode",
damaged children : [[4]?QuadNode",
That single fact explains both signals tri damage detects (doubled bracket, odd quote count). The candidate patch is therefore one character at a known offset, and inverting it is the same operation reversed.
The split is the load-bearing result
Applying the substitution and asking whether the result is a closed string is a decision procedure, not a guess.
107 lines / 12 classes yield a closed string. Every character of the type text survived; the repair only puts the delimiter back.
18 lines / 3 classes do not: the type text was TRUNCATED as well. [[]Const [, becomes "[]Const [, — the element type is gone. []Const []Const u8 and []Const [N]u8 are both plausible and the file holds no evidence either way. These get NO patch and go to needs-human-language-decision, owner: language owner.
Auto-repairing those would be a guess dressed as a fix, and unfalsifiable afterwards because the original is unrecoverable.
Double validation, because parsing alone proves nothing
Deleting the offending line also makes a file parse. So each applied candidate is checked twice: (1) t27c parse exits 0; (2) the specific field is back with a NON-EMPTY type AND no previously-present field vanished. Effect is one of parse-restored / still-malformed / ambiguous / needs-human-language-decision.
Two measurement units, and a hypothesis of mine that was wrong
My first reading of those 6 still-malformed classes was co-located UNRESTORABLE damage. Checked and false — none of those 7 files contains a destroyed line (0 of 0). The real cause was co-located damage from OTHER restorable classes, untouched by a single-class run. Hence a second mode, --combined, which repairs every restorable row per file:
effect
files
parse-restored
49
still-malformed
11
ambiguous
2
needs-human-language-decision
3
Neither unit replaces the other: per-class answers "is one rule enough for this shape", per-file answers "what does the rule achieve".
A third defect, found only because the first two were repaired
10 of those 11 still-malformed files fail at pub const Name(T) = struct { — Unexpected token in expression: KwStruct. That is a parser gap on generic const struct declarations, not corpus damage, and it was invisible while the files failed earlier for another reason. The 11th (bitset.t27) fails at Expected LParen, got KwTest — separate, unclassified.
Re-run differential on the repaired corpus
tri diffbin /tmp/t27c.base /tmp/t27c.fixed over the repaired corpus: 623 unchanged, 8 field-loss, 1 strict-improvement, 2 malformed-input-tradeoff, 0 unknown (was 616 / 13 / 1 / 4 / 0).
field-loss 13 -> 8, and 8 of 8 remaining field-loss files contain a destroyed line. The correlation is exact.
field-loss is NOT zero, so the gate on #2151 is NOT met and #2151 stays undecided. The residue is not a tool defect; it is the 18 destroyed lines, which cannot be repaired without a language decision.
Fixtures
15 positive (bootstrap/tests/fixtures/damage_classes/DC-*.t27), one per class, each carrying its shape, origin, candidate and expected effect. 6 negative (bootstrap/tests/fixtures/damage_negative/) pinning the false signals that made an earlier count a metric of the regex: latency bounds target : < 5000ns, match arms, multi-line array literals, function signatures, raw strings, and the intact convention.
Evidentiary power checked rather than assumed: the reconstructed first signal set fires on 6 of 6 negative fixtures; the current one fires on 0. On the real corpus the naive set reports 1378 lines against 125.
Not claimed
Not that the 125 are all the damage. tri damage checks two textual signals; damage producing a balanced, quote-even, plausible wrong type is invisible to it and nothing here bounds how much of that exists.
Follow-up to #2154. This is the measurement, not a corpus rewrite. No spec under
specs/is modified by any tool added here.Frozen before touching anything
docs/corpus/damage_snapshot_2026-08-15.json— 125 lines, 65 files, 15 shapes,corpus_sha256 = 1b5a37b7a89efb782db7efd2ca7af728d4ed48b1c13ac2a35088c7926b16afd9. Per row: class id, shape, file, line, field, verbatim rhs, 2 lines of context either side, and the file digest.tri damage-repairREFUSES to run if any digest has moved since the freeze.Class ids are
DC-+ 8 hex of sha256(shape), deliberately not a frequency rank, so adding a class later does not renumber a citation.The mechanism, established from the corpus
An intact field is
name : "TypeText",. Every damaged line has one defect: the opening quote of the type string was replaced by[.That single fact explains both signals
tri damagedetects (doubled bracket, odd quote count). The candidate patch is therefore one character at a known offset, and inverting it is the same operation reversed.The split is the load-bearing result
Applying the substitution and asking whether the result is a closed string is a decision procedure, not a guess.
[[]Const [,becomes"[]Const [,— the element type is gone.[]Const []Const u8and[]Const [N]u8are both plausible and the file holds no evidence either way. These get NO patch and go toneeds-human-language-decision, owner: language owner.Auto-repairing those would be a guess dressed as a fix, and unfalsifiable afterwards because the original is unrecoverable.
Double validation, because parsing alone proves nothing
Deleting the offending line also makes a file parse. So each applied candidate is checked twice: (1)
t27c parseexits 0; (2) the specific field is back with a NON-EMPTY type AND no previously-present field vanished. Effect is one ofparse-restored/still-malformed/ambiguous/needs-human-language-decision.Two measurement units, and a hypothesis of mine that was wrong
Per-class run: 6 parse-restored, 6 still-malformed, 0 ambiguous, 3 needs-human-language-decision.
My first reading of those 6 still-malformed classes was co-located UNRESTORABLE damage. Checked and false — none of those 7 files contains a destroyed line (0 of 0). The real cause was co-located damage from OTHER restorable classes, untouched by a single-class run. Hence a second mode,
--combined, which repairs every restorable row per file:Neither unit replaces the other: per-class answers "is one rule enough for this shape", per-file answers "what does the rule achieve".
A third defect, found only because the first two were repaired
10 of those 11 still-malformed files fail at
pub const Name(T) = struct {—Unexpected token in expression: KwStruct. That is a parser gap on generic const struct declarations, not corpus damage, and it was invisible while the files failed earlier for another reason. The 11th (bitset.t27) fails atExpected LParen, got KwTest— separate, unclassified.Re-run differential on the repaired corpus
tri diffbin /tmp/t27c.base /tmp/t27c.fixedover the repaired corpus: 623 unchanged, 8 field-loss, 1 strict-improvement, 2 malformed-input-tradeoff, 0 unknown (was 616 / 13 / 1 / 4 / 0).field-loss 13 -> 8, and 8 of 8 remaining field-loss files contain a destroyed line. The correlation is exact.
field-loss is NOT zero, so the gate on #2151 is NOT met and #2151 stays undecided. The residue is not a tool defect; it is the 18 destroyed lines, which cannot be repaired without a language decision.
Fixtures
15 positive (
bootstrap/tests/fixtures/damage_classes/DC-*.t27), one per class, each carrying its shape, origin, candidate and expected effect. 6 negative (bootstrap/tests/fixtures/damage_negative/) pinning the false signals that made an earlier count a metric of the regex: latency boundstarget : < 5000ns, match arms, multi-line array literals, function signatures, raw strings, and the intact convention.Evidentiary power checked rather than assumed: the reconstructed first signal set fires on 6 of 6 negative fixtures; the current one fires on 0. On the real corpus the naive set reports 1378 lines against 125.
Not claimed
tri damagechecks two textual signals; damage producing a balanced, quote-even, plausible wrong type is invisible to it and nothing here bounds how much of that exists.cost, and the full-run hang is still undiagnosed.