Repository navigation
spec(tri/pr): preflight -- the own-language budget from the merge base and the developer-home-path scan (Closes #11070) - #11125
Merged
Conversation
… developer-home-path scan are two more steps and rules (Closes #11070) specs/tri/pr/preflight.t27 gains STEP_BUDGET and STEP_DEVHOME (the steps become 19) and R_BUDGET and R_DEVHOME (the rules become 13, kept stays the last). budget: the step compiles gen/c/policy/own_language.c as it is at the merge base of origin/master and HEAD -- never the branch's copy -- around a one-line main that calls check_budget, and feeds it git diff --numstat --no-renames BASE...HEAD, as the "Foreign-line budget" step of .github/workflows/own-language.yml does. The numstat goes to a file first, so a git that fails leaves the gate no empty input to pass on. A line of the gate's own text, or its exit, fails the rule; exit 0 with no output passes; anything else (a compile error, no cc, a git that failed) is UNREAD. devhome: the step runs python3 -I tools/check_devhome_paths.py. Exit 0 with its OK line passes. Exit 1 with FAIL lines fails only for a finding that names a file the branch changes (new, grew, shrank, fixed), or for any finding when the branch edits the baseline or the scan itself; a finding on another file is master's own and does not fail the branch. A path git quoted cannot be matched against the scan's text, so it is UNREAD. Exit 2 (no baseline, grep failed), a crash and any other shape are UNREAD. Tests first: 5 new (budget verdicts, budget fails closed, the merge-base gate command, devhome verdicts, devhome fails closed) plus the steps, labels and worst-exit tests extended; 24 tests, 0 vacuous. The PR #10538 head 1e20cfb (+9/-0 in cli/tri/src/main.rs) is a fixture: the gate compiled from its merge base prints the shrink-only line and exits 1, the rule reads FAIL. changes_under replaces the loop in touches_census (no copied body). Generated Rust and seal are regenerated by t27c; no glue change (cli/tri/src/prcheck.rs is not touched). Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Contributor
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #11070
tri pr preflight(specs/tri/pr/preflight.t27, see #10190) gets the two checks the t27o loop still ran by hand before every push: the own-language foreign-line budget compiled from the merge base, and the developer-home-path scan. A lane learns about both from one command, before CI, instead of from a red check.What changed (specs/tri/pr/preflight.t27, its generated Rust, its seal)
STEP_BUDGET(17), onceR_BUDGET(10)gen/c/policy/own_language.c, compiled around the same one-linecheck_budgetmain as.github/workflows/own-language.yml, fedgit diff --numstat --no-renames BASE...HEAD.STEP_DEVHOME(18), onceR_DEVHOME(11)python3 -I tools/check_devhome_paths.py.STEPS17 -> 19,NO_STEP17 -> 19,RULES11 -> 13;R_COUNT("kept") moves 10 -> 12 and stays the last rule and the default ofrule_name/rule_why. Print order: ... census, budget, devhome, kept. One helperchanges_under(c, lit)is new for the baseline test andtouches_censusnow calls it (no copied loop);finding_pathandnames_homeread the scan's finding lines.Verdicts:
cc, a failedgit, a missing section) is UNREAD. The gate comes only from the merge base: there is no fallback to the branch's copy (CI falls back to HEAD only while the base predatescheck_budget; here that case reads UNREAD, and rulebasefails it anyway). The numstat goes to a file first, so agitthat fails leaves the gate no empty input to pass on.OK:line is PASS. Exit 1 withFAIL new|grew|shrank|fixed <path>lines fails only for a path the branch changes (any status, so a deleted baseline file is caught byFAIL fixed), or for any finding when the branch editstools/devhome_baseline.txtor the scan itself. A finding on another file is master's own and does not fail the branch ("own defects only"). A changed path git had to quote cannot be compared with the scan's text, so it is UNREAD when the scan has findings. Exit 2 (no baseline, grep failed), a traceback, a missingpython3and any other shape are UNREAD.Evidence: PR #10538 (head 1e20cfb, +9/-0 hand lines in cli/tri/src/main.rs)
I ran the committed
step_cmd(STEP_BUDGET)text withHEADat 1e20cfb andorigin/masterat 2e2ca5f (merge base b4fc955):That output, framed as
@@ preflight 17 0 1 212, with the realgit diff --name-statusof the PR as the changes, goes through the new rule (a scratch spec thatuses the preflight functions, not committed):So the preflight reports
budget FAILfor #10538 and prints the gate's own line as evidence, with the spec'srule_why: "the foreign-line budget (the merge base's own_language gate) refuses this diff: at most 40 hand-written foreign lines added per file and 80 per diff, never more added than deleted -- write the logic in .t27 and generate it". The same line is committed as the fixtureBUDGET_OUTofrule_budget_fails_on_the_gates_own_output.Negative controls, real runs: the same step text with
HEAD= origin/master exits 0 with 0 bytes of output (PASS); on this branch the budget step exits 0 with no output and the devhome step printsOK: 29 file(s), 37 occurrence(s), all pinned in tools/devhome_baseline.txt(PASS). The four finding shapes of the home-path scan were captured from the real script in a scratch tree; the committed fixtures use them (paths shortened).Tests
t27b test specs/tri/pr/preflight.t27: 24 passed, 0 failed, 1 invariant held.t27c test-report specs/tri/pr/preflight.t27 --specs-dir specs: 24 pass, 0 FAIL,vacuous passes 0 of 24.t27c seal specs/tri/pr/preflight.t27 --savethen--verify: all four hashes MATCH;gen-rustregenerated, byte-identical on a second run, and the base spec reproduces the base file byte for byte with the same binary.t27c check: Typecheck OK.rule_budget_fails_on_the_gates_own_output,rule_budget_fails_closed,the_budget_gate_is_compiled_from_the_merge_base(noHEAD:gen/c/..., no#include "gen/c/policy),rule_devhome_fails_for_a_file_the_branch_changes,rule_devhome_fails_closed. Extended:the_steps_are_named_and_ordered,the_changes_are_read_entry_by_entry,the_exit_is_the_worst_rule,each_rule_and_verdict_says_what_it_means, and the numbering invariant.Own language, DRY
check_allexits 0. Foreign lines added: 0.cli/tri/src/prcheck.rsis not touched.python3 -I tools/dupe_scan.py: on this branch and on a clean copy of the merge base 2e2ca5f the output is the same (632 group(s),1632duplicate bodies, "ok: no new duplicate body, and none of the known groups grew"; the total body count is 17432 -> 17434). No::error::finding on either side; the 15 inherited findings the lane brief mentions did not appear in this scan.dupe_scan.py --like specs/tri/pr/preflight.t27: "nothing in this file is written elsewhere".python3 -I tools/check_devhome_paths.py: OK on this branch; no developer-home literal in the diff.The glue
The task brief says the glue is
cli/tri/src/prcheck.rspreflight. It is not on master:docs/now/2026-10-18-pr-preflight.mdrecords it as parked (38 lines, refused by the foreign-line budget), and no ref in the local object store carries it. So there is no glue to change and none was read. The new steps need only what the spec header already promises:sh -c step_cmd(k)for every stepstep_runsaccepts, run once (they are notstep_each), at the repository root, noSPEC,T27CorTRI. When the glue lands it must iterate0..STEPSand0..RULESas the header says; if it hard-codes 17 and 11 it needs the same two numbers changed.Not run
tri pr preflightitself (no glue, notribuild; the cargo build was out of scope for this lane).t27c test-reportover the corpus,t27c suite --ratchet,tools/check_seal_coverage.pyandtools/check_seal_currency.py(they needtarget/release/t27c, which is not built here),tri types ratchet(the diff declares no struct or enum)..trinity/seals/land_TriLand.jsonlists preflight in its closure with the previous spec hash.t27c seal --verifydoes not read the closure (it prints all hashes MATCH for land) andt27b test specs/tri/land/land.t27still passes 26/26, so land was not re-sealed (outside the issue boundary); a re-seal would only refresh that closure entry.docs/reports/t27b_expectations.json(the preflight row stayspass) or to.claude/skills.🤖 Generated with Claude Code