Skip to content

chore(specs): untrack specs/scratch -- 455 files, 578 MB, 64.5% of the tracked tree - #2283

Merged
gHashTag merged 1 commit into
masterfrom
chore/untrack-specs-scratch
Aug 20, 2026
Merged

chore(specs): untrack specs/scratch -- 455 files, 578 MB, 64.5% of the tracked tree#2283
gHashTag merged 1 commit into
masterfrom
chore/untrack-specs-scratch

Conversation

@gHashTag

Copy link
Copy Markdown
Owner

Closes #2282

The repository owner asked for specs/scratch/ to stop being tracked.

Added to .gitignore and removed from the index with git rm -r --cached.
Nothing is deleted from any working tree -- every file stays on disk for
anyone who has it, now ignored.

What this removes

Measured against the base commit bffd38982 with git ls-tree -r -l:

group files bytes
specs/scratch/*_bench_* 352 606,058,170
hand-written witnesses 103 55,518
total 455 606,113,688 (578.0 MiB)

The tracked tree at that commit is 939,857,424 bytes, so this is 64.5% of it,
and 99.99% of those bytes are one generated family. The cost was never one wave's
drafts -- each wave committed its own on top of every prior wave's.

Scratch is where a wave thinks out loud. It is not a source of truth: zero use scratch appears anywhere in the tree, no spec outside it imports one, and the
corpus ratchet already excluded it by construction (bootstrap/src/suite.rs,
is_scratch()).

Files changed: 914

count what
D 455 specs/scratch/** -- index only
D 456 .trinity/seals/scratch_*.json -- index only
M 3 .gitignore, docs/NOW.md, tools/specs_generate_baseline.txt

Dependents moved in the same commit

456 seals. tools/check_seal_coverage.py resolves spec_path against the
filesystem, and CI checks out a fresh clone -- so untracking the specs alone
would turn every .trinity/seals/scratch_*.json into dangling. None is in
tools/seal_baseline.txt (0 of its 209 lines mention scratch). They are
untracked with the specs, which is the fix the gate's own message prescribes:
"the spec was committed and later deleted. Remove the seal with it, or restore
both."
They were not baselined -- that would have written 456 lines of
permanent debt.

The two sets coincide exactly: every seal named scratch_* has a spec_path
under specs/scratch/, and every seal with such a spec_path is named
scratch_*. They cover all 455 specs (one spec,
w825_bench_module_469x2p6_aos_var_call_write.t27, carries two seals).

58 baseline lines. The Emit Bit-Exact Gate enumerates via git ls-files *.t27, so the corpus drops 1196 -> 741 and 58 of the 348 lines in
tools/specs_generate_baseline.txt read as fixed, printing NOTE 58 spec(s) in the baseline now generate. That would be false -- they are gone, not fixed. All
58 dropped (348 -> 290); each was verified to name a file in the untracked set.
The gate does not fail on fixed, so this is a truth fix, not a red one.

Gate impact, measured

Seal Coverage is already red on master and stays at exactly the same 131.
Run 32324107310 on bffd38982 -- the exact base of this branch -- reports FAIL: 131 seal(s) newly do not hold, and the eight most recent master runs all failed.
Those 131 are stale/dangling seals in specs/tri/, specs/fpga/, compiler/
and elsewhere; none has anything to do with scratch, and re-sealing them needs a
built t27c.

The delta was measured rather than assumed: CI's failing-seal name set from run
32324107310 was diffed against a run of the same script over this branch's tree.
0 seals fail on master that do not fail here, and 0 scratch seals fail here.
Without the seal removal the count would have gone 131 -> 587.

Corpus ratchet: unchanged, by construction.
docs/reports/suite_expectations.json holds 221 entries against
max_entries: 221, none under scratch. The only difference is the log line
741 of 1196 -> 741 of 741.

Honesty limits (BINDING)

  • This does not shrink the repository's history. The blobs remain in git
    objects forever. git clone still transfers all 578 MB and every existing
    clone is exactly the size it was. Only git filter-repo plus a rewrite of
    every branch and tag would reclaim that space, and it would break every open
    PR, every fork, and every commit SHA in the tree's own records. This stops
    the growth from here. It reclaims nothing already paid for.
  • Two suite phases silently lose their corpus, and nothing turns red.
    collect_t27 returns Ok(vec![]) for a missing directory rather than
    erroring, so on a fresh clone Phase 3b gen-verilog yosys smoke falls from 482
    to 27 targets (94.4%; this phase is not filtered by --corpus-only, so it
    is the one real coverage loss), and Phase 3d/3e Icarus + cocotb falls 155 -> 0
    (local-only; no workflow passes those flags). Both print green. Read them as
    untested, not as passing.
  • Only 287 of the 455 files are re-derivable from committed code. 303
    generators scripts/gen_w<NNN>.py exist and are deterministic -- none
    references random, time, datetime, uuid, the environment, or the
    network -- but they cover 279 of the 383 wave numbers present. The other 168
    files exist only in git history. Recoverable, not reproducible.
  • 281 orphaned Icarus baselines were left tracked, deliberately.
    .trinity/icarus-baselines/specs/scratch/ is now unreachable in CI. It is
    20,248 bytes and removing it would also require editing 5 lines of
    tools/json_parse_baseline.txt. Out of scope; it costs nothing and fails
    nothing.
  • This PR does not leave CI green and does not claim to. Seal Coverage is red
    before and after at the identical 131. It is not one of the four required
    contexts (check-now-freshness, check, validate, check-linked-issue), so
    it does not block merge -- worth saying out loud, because
    docs/BRANCH-PROTECTION.md lists it as required and the live ruleset does not.
  • Stale prose was not chased. docs/CORPUS-RATCHET.md:96, the comment at
    suite.rs:39, and corpus-ratchet.yml:22 quote 606,113,688 bytes as a live
    measurement of the tracked tree. Still true of history, no longer true of a
    fresh checkout.

…e tree

The repository owner asked for specs/scratch/ to stop being tracked. Added to
.gitignore and removed from the index with `git rm -r --cached`. Nothing is
deleted from any working tree.

455 files, 606,113,688 bytes at bffd389. 352 of them are one generated family
(*_bench_*, 606,058,170 bytes); the other 103 are hand-written witnesses totalling
55,518 bytes. The tracked tree is 939,857,424 bytes, so this is 64.5% of it. The
cost is accumulation: each wave committed its drafts on top of every prior wave's.

Nothing outside scratch imports it (zero `use scratch` in the tree) and the corpus
ratchet already excluded it by construction (bootstrap/src/suite.rs, is_scratch()).

Two dependents move in this same commit:

- 456 seals .trinity/seals/scratch_*.json are untracked with the specs.
  check_seal_coverage.py resolves spec_path against the filesystem, so on a fresh
  clone each would become dangling. None is in tools/seal_baseline.txt (0 of 209
  lines), so leaving them would take Seal Coverage from 131 failures to 587.
  Removing them is the fix the gate's own message prescribes; baselining them
  would have written 456 lines of permanent debt.

- 58 lines of tools/specs_generate_baseline.txt naming scratch specs are dropped
  (348 -> 290). The Emit Bit-Exact Gate enumerates via `git ls-files *.t27`, so the
  corpus drops 1196 -> 741 and those 58 would read as fixed, printing a false
  "58 spec(s) in the baseline now generate". The gate does not fail on fixed, so
  this is a truth fix, not a red one.

Honesty limits, recorded in full in docs/NOW.md:

- This does NOT shrink history. The blobs remain in git objects; clone size is
  unchanged. Only filter-repo plus a rewrite of every branch would reclaim it, at
  the cost of every open PR, fork, and recorded SHA. This stops growth from here.
- Phase 3b gen-verilog yosys smoke silently falls 482 -> 27 targets on a fresh
  clone and Phase 3d/3e Icarus falls 155 -> 0, because collect_t27 returns an empty
  vec for a missing directory. Both print green; read them as untested.
- 168 of the 455 files have no committed generator and exist only in history.
- Seal Coverage is already red on master at 131 seals, unrelated to scratch. This
  change leaves it at exactly 131 -- measured against CI run 32324107310, whose
  failing set intersects this branch's exactly, with zero scratch seals in either.

Closes #2282
@github-actions

Copy link
Copy Markdown
Contributor

PR Dashboard

Generated at: 2026-08-20 02:39:10 UTC

Summary

Status Count
Total Open PRs 19
PRs with Failing Checks 4
PRs with All Checks Green 15
READY 7
FAILING 4
PENDING 0

Seal Status

  • ⚠️ STALE -- sha256(compiler.rs)=cbbfac87dff3 != 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).

@github-actions

Copy link
Copy Markdown
Contributor

📓 NotebookLM Notebook linked to this PR

This notebook contains session context, decisions, and artifacts for this work.

@gHashTag
gHashTag merged commit 2255e4c into master Aug 20, 2026
17 of 21 checks passed
gHashTag added a commit that referenced this pull request Aug 20, 2026
…source (#2285)

suite.rs has carried a non-empty floor for the ORACLE since W628 and never
for the TARGETS. load_expectations returns Ok(None) for a missing ledger,
documented as "never an empty ledger", and the ratchet turns that into
"RATCHET: FAIL -- Absence is not amnesty (T31)". Ten lines away, collect_t27
returns Ok(Vec::new()) for a directory that is not there; every phase
iterates it happily, run_phase returns (0, 0), and the phase prints
"0 passed, 0 failed" into a suite that then prints ALL TESTS PASSED.

No phase in run_comprehensive checked files.is_empty(), and no test anywhere
asserted a phase's target count.

It was already live. Untracking specs/scratch (#2283) took icarus-simulate
and icarus-cocotb from 155 targets to 0 and gen-verilog-yosys-smoke from 482
to 27. 281 baselines are still tracked under
.trinity/icarus-baselines/specs/scratch/ -- golden files whose subject no
longer exists and whose comparing phase has no targets. Nothing said a word,
and the ratchet could not: its 221 ledger entries include 0 under scratch.

Adds require_targets(phase, source, files) and its single-file form
require_target_file. Both name where the targets were supposed to come from,
because every instance of this bug looks identical from the summary line and
completely different at the source. Six call sites: the post-corpus-only
spec lists (phases 1-6), phase 1c's gf16 spec (which reported "skipped (spec
not found)" for a conformance gate that checked nothing), phase 3b's smoke
list, phases 3d and 3e, the relative "specs" root shared by the phase 6
metrics, and phase 7's catalog gate -- which sat behind a bare
"if cat.is_file()" with no else and printed "gate failures: 0" followed by
"the catalog gate are all clean" for a gate that never ran.

collect_t27 is deliberately unchanged: specs/scratch is legitimately absent
since #2283, so the walker must keep returning an empty vec. Only the call
site knows whether zero is a defect or a configuration. A test pins that
division of labour.

Four named opt-outs, all "the phase does not run": the standalone
specs_scratch binding, phase 3b without yosys, phase 3d without its flag or
iverilog, phase 3e without --cocotb.

No CI effect today: corpus-ratchet.yml walks 650 corpus specs from the repo
root, both fixed specs are tracked, and it installs neither yosys nor
iverilog. Every guard passes. Running the suite with --icarus-simulate now
fails, naming specs/scratch, which is the honest outcome.

Does not restore the coverage the untrack removed, and does not detect a
phase that shrank without reaching zero. Not compiled locally; suite.rs was
parse-checked with rustfmt only. See docs/NOW.md.

Closes #2284

Co-authored-by: Claude <claude@anthropic.com>
gHashTag added a commit that referenced this pull request Aug 20, 2026
…ero (#2287)

#2285 gave suite.rs a floor for the TARGET LIST. Two sites of the same shape
on the INPUT side were left, and both reported a clean pass when what they
read was missing or unreadable.

The discipline was already in the file. load_expectations returns Ok(None) for
a missing ledger and never an empty one -- "T31 is the bug where a gate treats
'no oracle' as 'pass'" -- and the ratchet turns that None into
"RATCHET: FAIL -- Absence is not amnesty (T31)". Neither site followed it.

A. Phase 7 catalog gate asked the working directory, not the tree.
require_target_file closed the silent skip in #2285, but both operands stayed
RELATIVE, so what the gate examined -- and whether the suite aborted -- depended
on the cwd the binary was invoked from, and the failure named a relative path
that cannot distinguish a wrong cwd from a lost file. Both are now joined onto
the canonicalized repo root. The Err arm also still failed open: with the file
proven present, reaching it meant the gate could not READ a file that exists, yet
it printed one line, left gate_fail untouched, and the block below still printed
"(lexer/parser conformance and the catalog gate are all clean)". It now bails.

B. A corrupt baseline was byte-identical to a clean one.
load_gen_verilog_smoke_baseline collapsed six conditions into HashSet::new()
behind an eprintln!: missing file, unreadable file, invalid JSON, no
expected_failures key, that key not an array, a non-string entry inside it. The
caller set summary.baseline_failures = 0, which feeds summary.acceptable. The
tracked baseline legitimately holds "expected_failures": [], so the fail-open
path produced exactly the same output as the real file -- the right answer for
the wrong reason on every run to date, which is why nothing caught it.

It now returns anyhow::Result<Option<HashSet<String>>>: Ok(None) is absent, Err
is present-but-unparseable, Ok(Some) is present-and-valid, and only the third
may produce a count. That is load_expectations' signature and its reason. The
caller decides in the open, and decides FAIL -- the file is tracked, so absence
is a broken path, not a configuration.

Tests: a_missing_baseline_is_none_not_an_empty_baseline is the counterpart, for
the BASELINE, of a_missing_ledger_is_none_not_an_empty_ledger, which has kept
absence out of the ORACLE since W628 while nothing kept it out of the baseline.
a_corrupt_baseline_is_an_error_not_an_empty_baseline runs four corrupt payloads
and asserts each is an Err naming the file.

No criterion moved. CATALOG_ALLOWED, catalog_gate::run, the acceptable formula
and the baseline file are untouched. With cwd == repo root -- the only
configuration these gates have run in -- the resolved paths are identical and
no finding changes.

Effect on CI today: none. corpus-ratchet.yml runs from the repo root with both
files present, so every guard passes and every printed number is identical.

Honesty limits: this does not restore the 482 -> 27 coverage #2283 took from
phase 3b, does not detect a phase that shrank without reaching zero, and phase
3b still cannot fail CI because it never calls record(...) -- a separate defect,
unfixed. Not compiled: parse-checked with rustfmt only, so types and borrows are
unproven until CI's cargo build.

Closes #2286.

Co-authored-by: Claude <claude@anthropic.com>
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.

chore(specs): untrack specs/scratch -- 455 files, 578 MB, 64.5% of the tracked tree

2 participants