Skip to content

fix(t27c): seal --verify reads the committed gen file; compile refuses a hand-written output (draft, needs owner-approved-foreign) - #10481

Draft
gHashTag wants to merge 2 commits into
masterfrom
claude/gen-file-fix
Draft

gHashTag wants to merge 2 commits into
masterfrom
claude/gen-file-fix

Conversation

@gHashTag

Copy link
Copy Markdown
Owner

Refs #10457. Draft, for the owner's owner-approved-foreign label: this edits existing Rust in bootstrap/src/main.rs. Depends on #10472 (the specs); this branch sits on top of it, so until #10472 lands the diff also shows the two specs, their seals and the ledger lines.

What it does

The rules are the generated functions of specs/verified/gen_file_check.t27 and specs/compiler/compile_output.t27, wired in through #[path] modules (bootstrap/gen/rust/verified/gen_file_check.rs, bootstrap/gen/rust/compiler/compile_output.rs, written by t27c gen-rust). main.rs only gathers the inputs and prints.

  • seal --verify (follow-up A). After the hash check, each committed bootstrap/gen/rust/<rel>.rs, gen/rust/<rel>.rs, gen/c/<rel>.c and gen/verilog/<rel>.v is compared with what gen-rust, gen-c and gen-verilog emit today. An absent file is fine. Drift, an unreadable file, or a file whose backend no longer generates the spec fails with exit 1 and names the file.
  • compile (follow-up B). Never writes over the input spec, even with -o. Never overwrites an existing file that lacks generated by t27c in its first 5 lines, unless -o names it.

To read the same bytes the gen commands print, the three identical bodies of run_gen, run_gen_c and run_gen_rust become one gen_resolved(). Foreign budget: main.rs +40/-60, so hand-written Rust shrinks by 20 lines. The two .rs files are generated.

Known limits

  • gen/json is not read: gen-json renders a spec-specific shape and has no in-memory producer.
  • Verilog is compared with compile_verilog_at_reporting on the unresolved source, which is what gen-verilog does. A file written with --with-sva would show as drift; none is committed today.

Lab results (Railway, this branch built from 982894c + #10472)

A.

case t27c seal <spec> --verify
untouched digest_cache, bench_boards, die_binding, claw/gates, and both new specs all hashes MATCH, exit 0
bootstrap/gen/rust/verified/digest_cache.rs truncated to 200 bytes DRIFT, VERIFICATION FAILED, exit 1
pub fn hand_edit() {} appended to bench_boards.rs DRIFT, exit 1
file restored with git checkout all hashes MATCH, exit 0

B. Against specs/x/k.t27:

case result
hand-written k.zig refused, exit 1, file unchanged
hand-written k.v (--backend verilog) or k.c (--backend c) refused, exit 1, file unchanged
-o specs/x/k.zig written, exit 0
generated k.zig, k.v or k.c rewritten, exit 0
-o specs/x/k.t27 refused, "it is the input spec", exit 1, spec unchanged

Tree-wide (t27c suite, Phase 5 Seal Verify). 2116 specs pass and 158 fail. 143 of the failures exist without this change: hash mismatches and missing seals. The new check fails 15 specs over 16 committed files:

area files
bootstrap/gen/rust/base/ ternary_add, ternary_encoding, ternary_memory
bootstrap/gen/rust/memory/ formula_embed, semantic_search
gen/c/numeric/ gf16.c
gen/verilog/numeric/ gf16.v
gen/rust/tools/t27o/ rust_convert
gen/rust/tri/t27b/ blockers, coerce_plan, const_div_plan, elf, lencall, macho, tuple_local_plan, verdict_key

Each one checked by hand is genuinely stale. gf16.c and gf16.v date from #408, elf.rs keeps an older bytes_are(Vec<u8>) signature, and rust_convert.rs is one test behind its spec. No ORPHAN and no UNREADABLE files turned up. Before this merges, those 16 files need regenerating or the check needs to start in warn mode. That choice is the owner's.

foreign-budget and own-language lefthook hooks pass; no --no-verify.

🤖 Generated with Claude Code

gHashTag and others added 2 commits October 18, 2026 20:24
…nd-written output

Two follow-ups of #10457, both reproduced on the Railway lab with t27c built
from master 982894c, written as .t27 with tests and negative controls.

specs/verified/gen_file_check.t27 (follow-up A). `seal --verify` regenerates
every backend in memory and never opens bootstrap/gen/ or gen/: a
digest_cache.rs cut to 200 bytes, and a bench_boards.rs with a hand-appended
fn, both verified "all hashes MATCH", exit 0. The rule compares a committed
gen file with what `t27c gen-<backend>` emits today, not with the recorded
gen_hash_*: gen-rust and gen-c resolve `use` first and seal does not, so for
bench_boards, die_binding and claw/gates the untouched file differs from the
seal while equal to its generator. 61 of the 124 committed gen files hash to
a recorded seal value, 63 do not. Absent is not drift; unreadable and
no-longer-generated fail closed; the file check adds to the seal check.
12 tests, 0 vacuous.

specs/compiler/compile_output.t27 (follow-up B). `t27c compile specs/x/k.t27`
overwrote a hand-written k.zig (k.v, k.c with --backend), and
`-o specs/x/k.t27` replaced the spec with its own Zig output, all exit 0. The
rule: the input spec is never the output; no file, write; -o naming the path
is consent; otherwise write only when "generated by t27c" is in the first 5
lines, and refuse an unreadable file. All 75 committed outputs next to a
same-stem spec carry the marker (14 on line 2, 61 on line 3), so the rule
refuses none of them. 10 tests, 0 vacuous.

Sealed without --force, --verify all hashes MATCH. Eight hand-made mutants
(four per spec) each fail at least one test. t27b passes both natively
(aarch64 under qemu, 22 tests), recorded in docs/reports/t27b_expectations.json.

Refs #10457

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…s a hand-written output

Applies specs/verified/gen_file_check.t27 and specs/compiler/compile_output.t27
(#10472) to t27c. The decisions are the generated functions, wired in through
#[path] modules; main.rs only gathers the inputs.

seal --verify: after the hash check, each committed bootstrap/gen/rust/<rel>.rs,
gen/rust/<rel>.rs, gen/c/<rel>.c and gen/verilog/<rel>.v is compared with what
gen-rust, gen-c and gen-verilog emit today. Absent is fine; drift, unreadable
and no-longer-generated fail with exit 1 and name the file. gen/json is not
read yet: gen-json renders a spec-specific shape with no in-memory producer.

compile: never writes over the input spec, and never over an existing file
without "generated by t27c" in its first 5 lines unless -o names it.

To read the same bytes the gen commands print, the three identical bodies of
run_gen, run_gen_c and run_gen_rust become one gen_resolved(), so main.rs is
+40/-60 and the foreign budget shrinks.

Refs #10457

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

PR Dashboard

Generated at: 2026-10-18 13:48:48 UTC

Summary

Status Count
Total Open PRs 50
PRs with Failing Checks 49
PRs with All Checks Green 1
READY 0
FAILING 49
PENDING 0
NO CHECKS YET 0

These columns do not partition: 0 + 49 + 0 + 0 = 49, and there are 50 open PRs. A PR is being counted twice or not at all.

Seal Status

  • ⚠️ STALE -- sha256(compiler.rs)=fad12492937a != manifest seal=87e5cbd3ad94.
    The committed NMSE numbers were certified against an older compiler.rs.
    Run scripts/reseal-check.sh locally for the two-step reseal command (advisory; not a merge gate).

This was referenced Oct 18, 2026
This was referenced Oct 18, 2026

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant