213 seals record no generation, and every check reads them as healthy - #2865
Conversation
A seal stores a spec's hash and the sha256 of what the compiler generates from it for four backends. When the spec does not parse, `t27c seal` exits 0 and writes `gen_hash=none` four times. Every check then agrees with it. Freshness compares spec_hash: it matches. Drift recomputes and compares: `none` equals `none`, zero drift, and the summary reads "Every seal of every spec that exists matches what the compiler produces from it right now". Coverage sees a seal file and counts the spec as covered. Three correct checks, three greens, and the record says generation did not happen. The repository already refuses to WRITE one -- `is_sealable()` guards `drift --fix`, `sync-twins` will not propagate one -- and nothing read the ones on disk. tri seals hollow the census, by directory tri seals hollow --why the compiler's error on each, grouped by kind 104 distinct specs, 39 error kinds, largest covering 23: a dozen parser gaps, not 104 repairs. Three of the seals name files that are not specs at all -- two Markdown and a `.tri`. Also: `t27c validate` printed "VALIDATION: FAILED" and exited 0. It is the command that produced the first reading here. No workflow runs it, which is why this was never noticed; the reason to fix it anyway is that whoever wires it up next would inherit a gate that cannot fail. FAILED now exits 1, PASSED still exits 0, both verified. Controls: a real seal forced to `none` moves the count 213 -> 214; a hollow seal given four hashes moves it 213 -> 212. Five unit tests on the error-kind normaliser, including the one that catches over-merging. Refs #2864, #2767, #2774 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The first commit implied nothing counted these specs. That is wrong:
`tools/specs_generate_baseline.txt` is a debt ledger of exactly this, opening
with "Each line is a debt", and 101 of the 104 hollow-sealed specs are already
in it. One grep before claiming novelty would have caught it.
What survives measurement is narrower and still worth the tool: the same fact
is recorded twice, one record calls it debt and the seal side reads it as
covered, fresh and undrifted. So the census reconciles rather than competes:
against tools/specs_generate_baseline.txt, which calls each line a debt
101 already recorded there
3 hollow seal, NOT in the ledger
2 in the ledger with no hollow seal
The 3 are not specs -- two Markdown and a `.tri` -- and the ledger is right to
omit them. The 2 have no seal file at all; checked, not inferred, and both
still fail to parse, so it is a coverage gap and not a contradiction between
the two records.
The summary no longer says a hollow seal "passes every check this repository
has". It passes every SEAL check, which is the accurate claim.
Control: a line removed from the ledger moves 101 -> 100, tree restored clean.
Two more unit tests: the ledger's error column carries pipes of its own on
specs whose failing token IS `|`, so the path column splits on the FIRST pipe.
Refs #2864
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
CI on this branch auto-ran Issue Gate and NotebookLM Gate only. Fetched the missing measurement with
So the changes are green in real CI, not only locally. The non-firing trigger is a separate matter and does not belong to this PR — but it means a green PR page here was, once again, about frequency rather than health. |
# Conflicts: # .claude/skills/ci-gates/SKILL.md
|
📓 NotebookLM Notebook linked to this PR
This notebook contains session context, decisions, and artifacts for this work. |
PR DashboardGenerated at: 2026-08-29 19:05:50 UTC
Summary
Seal Status
|
…arries master added sections through 311 while this branch was open, so the two sections here move to 312 and 313. Their content is unchanged. While resolving, line 7790 of the file on master turned out to be a bare `<<<<<<< HEAD` with no matching `=======` -- committed in 2c0ce54 (#2574) and still there. Removed. `tri skill check` reports OK with it present, which is a gap in the checker and a separate change. Refs #2864
|
📓 NotebookLM Notebook linked to this PR
This notebook contains session context, decisions, and artifacts for this work. |
PR DashboardGenerated at: 2026-08-29 19:12:04 UTC
Summary
Seal Status
|
|
📓 NotebookLM Notebook linked to this PR
This notebook contains session context, decisions, and artifacts for this work. |
PR DashboardGenerated at: 2026-08-29 19:22:22 UTC
Summary
Seal Status
|
# Conflicts: # .claude/skills/ci-gates/SKILL.md
PR DashboardGenerated at: 2026-08-29 19:33:24 UTC
Summary
Seal Status
|
|
📓 NotebookLM Notebook linked to this PR
This notebook contains session context, decisions, and artifacts for this work. |
`scripts/verify_all_152.py` -- a verification script by its name, whose docstring promises 152 formulas at 50-digit precision -- carries eight unresolved `Updated upstream` / `Stashed changes` conflicts, two of them nested. `ast.parse` on it is a SyntaxError. It has been that way since f1fb145, the commit that introduced it: checked, there is no earlier clean revision to restore. Nothing imports it and nothing runs it. Nothing looked for the shape. A second marker sat in `.claude/skills/ci-gates/SKILL.md` from 2c0ce54 (#2574) until #2865 removed it by hand during an unrelated merge. `tri skill check` read that file and reported OK, because it checks section numbering. tools/check_conflict_markers.py 7592 files read, 1 carrying, 60 not read It abstains on a bare seven-equals line: that is an ordinary Markdown rule and this repository has hundreds, while git always writes the divider BETWEEN two LABELLED markers, so the labelled pair alone is sufficient. The gate builds its own patterns from `"<" * 7` rather than literals -- the first draft contained them and refused its own source, which the self-check caught. The workflow carries no `paths:` filter, and the reason is specific rather than inherited: a marker can land in any file, so a filter would be a filter on where the defect may hide. `verify_all_152.py` is recorded in the baseline WITH ITS REASON rather than repaired. Resolving it means choosing which of 152 numeric formulas is right, and that is the owner's call. The gate reports a baseline line that has outlived its debt, so the record cannot quietly become an excuse. Self-check covers six branches including both controls: a clean tree must stay silent, a bare divider must abstain, a planted marker must be seen at the right lines, a baselined file must be counted but not new, a baseline outliving its debt must be reported, and the gate's own source must be clean. Refs #2873, #2756, #2574 Co-authored-by: Claude <noreply@anthropic.com>
A seal stores a spec's hash and the sha256 of what the compiler generates from
it for four backends. When the spec does not parse,
t27c sealexits 0 andwrites
gen_hash=nonefour times. 213 of the 1311 spec seals on master arein that state.
The fact is known. What is not is that the same fact reads as health on the
seal side:
tools/specs_generate_baseline.txtEach line is a debt..trinity/seals/<m>.jsonnone; fresh, undrifted, coveredEvery seal check is individually correct while doing this.
seals freshcompares
spec_hashand it matches.seals driftrecomputes and comparesnoneagainstnone, reports zero, and prints "Every seal of every spec thatexists matches what the compiler produces from it right now." Seal Coverage
sees a seal file and counts the spec as covered. See #2864.
What this adds
--whyis the part that makes it actionable: 104 specs reported one line eachis 104 problems; grouped by kind with coordinates stripped it is 39 kinds,
the largest covering 23 specs — a dozen parser gaps, not 104 repairs.
It reports and writes nothing. Which gaps to close, and whether a hollow seal
should be deleted or kept as a marker, is the owner's call.
Two rows the ledger and the seals disagree on, both checked rather than
inferred:
docs/nona-03-manifest/PHI_LOOP_CONTRACT.md,.../SOUL.md,specs/sandbox/sandbox.tri.noneis the honest answer for Markdown; thequestion should not have been asked. The ledger is right to omit them.
bootstrap/src/codegen_python.t27,bootstrap/tests/goldring/cap_test.t27. Both still fail to parse, so this isa seal-coverage gap, not a contradiction.
The second change
t27c validateprintedVALIDATION: FAILED— 162 issues, 98 parse failures —and exited 0. It produced the first reading behind this PR. No workflow runs
it, which is why it went unnoticed; the reason to fix it anyway is that whoever
wires it up next inherits a gate that cannot fail. FAILED exits 1 now; PASSED
still exits 0, verified on a one-spec tree.
bootstrap/src/compiler.rsis untouched, sostage0/FROZEN_HASHstill matches.Controls
noneparse error near line N:×3|validateon a tree that passesTree restored clean after every mutation. 11 unit tests in
seals.Gates, run locally
seal coverage 0 (self-check 0, legend 8 of 8) ·
check_specs_parse.py0 ·seals fresh 0 · seals drift 0 · types ratchet 0 · skill check 0 ·
cargo test -p tri0.Two caveats stated rather than hidden:
cargo clippyhas 4 errors indlc10,the same 4 as master; and
cargo fmt --checkis red for this crate on mastertoo (38 diffs), so only
seals.rswas formatted — reformatting the other fourfiles would have been unrelated churn.
CI on this branch ran Issue Gate and NotebookLM Gate only.
cli-tri.ymlandbootstrap-tests.ymlboth have path filters that match these changes andneither produced a run; that is worth a look independently of this PR.
Refs #2864, #2767, #2774