diff --git a/.claude/skills/t27o/SKILL.md b/.claude/skills/t27o/SKILL.md index c004ff5fd0..36a2eebe34 100644 --- a/.claude/skills/t27o/SKILL.md +++ b/.claude/skills/t27o/SKILL.md @@ -61,7 +61,7 @@ For a `.zig` file there is no rustc oracle: the converted spec carries the file' 1. Read the ledger comment on #10522; `CronList` (delete duplicates after a restart); list running subagents. A lane a row calls running is not started again. The analog loop keeps its own ledger on #10486 and owns #10509 and `specs/analog/`: never start work there. 2. Anomalies before new work: open PRs of the epic that are red, conflicting or stale; a lane that reported done with no PR (`git ls-remote origin | grep t27o`); a seal that no longer verifies. 3. Sonnet 5.5 plans, implements and reviews (`specs/claw/model_route.t27`, #10929, owner 2026-10-19); Opus only after two failed attempts or on the owner's word. Two lanes at most from this loop while the analog loop runs on the same 8 GB Mac; one lane at a time edits `rust_convert.t27`. -4. Review before auto-merge, on the PR head: `t27b test` and once `t27c test-report` (vacuous 0) on every touched spec; `t27c seal --verify`; regenerate each gen file and compare byte for byte; `python3 -I tools/dupe_scan.py` and `--like ` (bodies -- `t27c dupes --name` only finds names; #10801 passed the name check with 13 copied bodies); the own-language budget compiled from the merge base (below); `python3 -I tools/check_devhome_paths.py` (#10646 brought nine `/Users/...` test literals); `tri types ratchet` when the diff declares a struct or enum (a fixture type named `Gate` clashed with crm-sellers' `Gate`: the types ratchet counts a second definition of a name as a conflict, so name fixture types uniquely); `cargo check -p tri`. A red is inherited only if the PR's failures are a subset of master's: run `dupe_scan` on the PR head AND on its merge base and `comm -23` the findings (against current master the base drift shows up as false extras). A spec that `use`s `rust_convert.t27` (spice, zig) carries it in its seal closure: re-seal it when rust_convert changes. +4. The local gate is `tri pr preflight --quick` (#11207; `tri pr preflight` adds the corpus ratchet, about 11 minutes): check, tests with vacuity, seal, types, dupes against the base, ledger rows, census, the own-language budget and the home-path scan; exit 0 all passed, 1 a rule failed, 2 evidence unreadable (never a pass). It does not run `check_seal_currency.py`, `check_seal_coverage.py` or the cargo tests: run those after an emitter or spec change. Review before auto-merge, on the PR head: `t27b test` and once `t27c test-report` (vacuous 0) on every touched spec; `t27c seal --verify`; regenerate each gen file and compare byte for byte; `python3 -I tools/dupe_scan.py` and `--like ` (bodies -- `t27c dupes --name` only finds names; #10801 passed the name check with 13 copied bodies); the own-language budget compiled from the merge base (below); `python3 -I tools/check_devhome_paths.py` (#10646 brought nine `/Users/...` test literals); `tri types ratchet` when the diff declares a struct or enum (a fixture type named `Gate` clashed with crm-sellers' `Gate`: the types ratchet counts a second definition of a name as a conflict, so name fixture types uniquely); `cargo check -p tri`. A red is inherited only if the PR's failures are a subset of master's: run `dupe_scan` on the PR head AND on its merge base and `comm -23` the findings (against current master the base drift shows up as false extras). A spec that `use`s `rust_convert.t27` (spice, zig) carries it in its seal closure: re-seal it when rust_convert changes. 5. Merge only green, then auto-merge (GraphQL `enablePullRequestAutoMerge`). It refuses with "in unstable status" while a NON-required check is red; when the four required checks (validate, check-linked-issue, parse-ratchet, own-language) are green and every red is master's, merge with `PUT /repos/gHashTag/t27/pulls/N/merge` and `{"merge_method":"squash","sha":""}` (the sha makes a late push fail the merge instead of slipping in). Turning auto-merge off does not hold a PR -- any actor with the token can re-arm it (#10801 merged five minutes after it was switched off). To hold a PR, convert it to a draft (`convertPullRequestToDraft`); `markPullRequestReadyForReview` when it may go. 6. Stacked PRs and squash merges: after the base merges, `git rebase --onto origin/master `, check `git diff HEAD -- ` is empty, push with `--force-with-lease=:`; auto-merge survives a force push. 7. A t27b change that makes ledger-blocked specs pass, or moves a blocker, edits `docs/reports/t27b_expectations.json` in the same PR (the rows and `max_not_pass` recounted; precedents #10862, #10999). The steward applies UNEXPECTED PASS and UNLISTED from a master run itself but refuses MOVED; a new spec's UNLISTED row is the steward's. @@ -82,6 +82,17 @@ This is the gate CI runs, compiled from the base revision. Most "never used" ite PR #10538 failed it with +9 / -0 at 1e20cfb34. +## Day-two lessons (2026-10-19/20) + +- Measure before you write a rule, and write it only above a stated threshold. Lane A5 (`Vec` parameters, ceiling 1 fn) and lane A6 (iterator chains, 17 to 32 fns) each saved a pull request by posting the table first and closing the issue as not planned. +- The Rust converted share is flat (9.93% to 9.88%): the bound is what t27 cannot say (heap, strings, closures, tuples), not missing converter rules. Conversion deletes about 1% of hand-written lines (#11149, #11159, #11168); the RFC `docs/now/2026-10-20-heap-free-collections-rfc.md` says build no construct yet (bar: a pilot rate of 15 in 100, best measured 1.3). +- An emitter fix moves the output of every spec it touches, and each needs its seal re-saved after reading the change. Run `python3 tools/check_seal_currency.py` and `python3 tools/check_seal_coverage.py` locally before pushing (#11192 lost an hour to 16 stale seals), diff the output over all tracked specs, and never call a seal "already stale on master" without reading master's CI. +- Say whether a count is of items or of fns, and over which sweep: 6,180 refused items over 16,057 fns was reported as 38.5%; the fns-only share is 30.8%. +- A lane cleans only its own named scratch directory, never a glob in `$TMPDIR` or the shared scratchpad (one wiped 29 files of other lanes). +- Free disk follows swap and load, not files: measure with `df` and the load, keep lanes to one job at a time, and delete a profile you do not need (`target-tri/debug` was 2.5 GB). +- A PR-body edit re-queues the required `check-linked-issue`: finish the body before the final CI wait. Merge a docs-only PR only after the checks that exist have completed. +- The first golden port (#11157) is the recipe for deleting hand Rust: issue, `tri t27o`, review the spec, keep the hand tests, gen-rust into `bootstrap/gen/rust/` (`git add -f`), delete the file, mount it from the parent `mod.rs`, then the real crate's `cargo check --all-targets` and tests, and a side-by-side run of old and new (756 million comparisons, 0 disagreements). + ## Traps met on this Mac - `.claude/skills/**` is not writable from the session's own worktree in the sandbox; a checkout that touches it half-applies (index changed, file unchanged). Work in a separate worktree: `git worktree add --no-track -b $TMPDIR/t27o-loop/wt-x origin/master`, then `git -C $TMPDIR/t27o-loop/wt-x config --worktree core.hooksPath .githooks`.