Repository navigation
verified: t27c signs receipts and run-record judges their level -- R3-1 tool half (Closes #7332) - #7363
Merged
Conversation
…-1 tool half (Refs #7332) WIP: lab build pending. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ck; lock ed25519-dalek resolved_path gave up on a path like base/missing/../repo/k (Path::file_name is None for ..) and returned it unnormalized, so a key path spelled through a missing directory escaped the inside-the-repository refusal. Walk the path component by component instead: canonicalize every existing prefix, apply . and .. lexically under a missing one. Caught by the r3_signed_receipt test on the Railway lab. Refs #7332 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
gHashTag
enabled auto-merge (squash)
October 7, 2026 08:19
12 of 62 tasks
Contributor
gHashTag
added a commit
that referenced
this pull request
Oct 7, 2026
…rigin/master (Closes #7371) (#7399) The Only-t27 gate had three holes, all used by #7363 (804 hand-written Rust lines in bootstrap/src/service.rs): - locally the exception list was read from the working tree, so a branch could list itself; - in CI the label owner-approved-foreign waived the whole check, and the label is applied through the same account the agents use; - an exception covered a whole file with no limit on how much it may grow. The rule now has check_budget() in specs/policy/own_language.t27: at most 40 added hand-written foreign lines per file and 80 per diff, read from `git diff --numstat --no-renames`. It reads no exception list and no label lifts it. Deletions are free; specs, generated roots, prose and data do not count; the gate's own foreign files (lefthook.yml, its workflow) do. Unreadable numstat lines fail closed. - gen/c/policy/own_language.c regenerated with t27c gen-c (Railway lab). - lefthook.yml: own-language reads the list from origin/master; a new foreign-budget command on pre-commit and pre-push. - own-language.yml: a budget step with no label condition, compiled from BASE (HEAD only while BASE predates check_budget). - own-language is now a required check in the master ruleset. Verified on the lab: 32/32 zig tests, the C test main exits 0, 19/19 hand mutants killed (limits 40/80 moved both ways, > vs >=, every counted kind dropped, protected/generated/own branches flipped, binary '-', empty path, digit bounds, base 10, the total and unreadable failures). Negative control: the #7363 merge diff gives 3 DENYs (service.rs, signed_receipt_reader.rs, the 80-line total). This diff adds 34 foreign lines. Committed by the owner with LEFTHOOK=0: the gate denies every local change to its own files, by design. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
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 #7332 (tool half; the contract half is #7344, on master as e436d84). Epic #6655, Round 3, item R3-1.
What changes
t27c receipt-key init | show.initmakes an Ed25519 key pair. The private key is a 32-byte seed with mode 600, written to$T27_RECEIPT_KEYor~/.config/t27/receipt-ed25519.key. It refuses a path inside the repository:..and symlinks are resolved first, and a subdirectory or a gitignored path still counts as inside. It never overwrites an existing key and never prints the key. The public half is committed as.trinity/keys/<key_id>.pub, wherekey_idis the first 16 hex characters of SHA-256 of the public key.showexits 0 if the key is registered, 1 if there is no key or it is not registered, and 2 if refused.t27c silicon --nonce <hex>signs every receipt when a key is present. The signed message is the domain linet27-receipt-v1followed by ninename=<json>lines in the spec's order, with the nonce inside the message. Without a key the receipt is written UNSIGNED and the tool says so: level NONE, no claim. A bad nonce (not hex, or under 16 bytes) or a refused key stops the run before any hardware work (exit 2).t27c run-record --challenge <hex> --require-level none|author|freshprints each receipt's authentication code and level, in the order ofsigned_receipt.t27: unsigned -> key not registered -> bad signature -> no nonce -> nonce is not the challenge. The run's level is the minimum over its receipts. Citable now means run-complete AND level >= required. A complete run below the required level printsNOT CITABLE at X -- the run reaches only Yand exits 1.Acceptance (from #7332)
missing/../repo/kand a symlink.--require-level none, so the R2 exit semantics are unchanged and nothing is claimed retroactively. The capstone's three receipt files were bench-local and gitignored, so this is pinned by tests on the same shape (a_receipt_from_before_the_rule_is_unsigned,one_unsigned_or_edited_receipt_lowers_the_whole_run), not re-run on those three files.Evidence (Railway lab t27c-lab, head 0742384)
cargo build --release -p t27c: clean. ed25519-dalek 2.2.0 was already in Cargo.lock through jsonwebtoken, so the lock gains one dependency line and no new crate.cargo test --bin t27c -- r3_signed_receipt r2_silicon_receipt run_record: 18/18.the_constants_are_the_specsparsesspecs/verified/signed_receipt.t27, so the Rust constants cannot drift from the spec.the_mirror_answers_the_specs_vectorsruns the spec's 10 vectors through the Rust mirror.--test signed_receipt_reader: 5/5. The test signs with ed25519-dalek over a message it builds itself, so writer and reader are checked independently.--test run_record_reader: 13/13, so R2-4 is unchanged.resolved_pathgave up on..under a directory that does not exist, sobase/missing/../repo/kescaped the inside-the-repository check.[7u8; 32], built in code; no key file is in the tree.Competitor comparison
t27 now has the same envelope as Gonka/EigenAI-class systems: host-key authorship plus verifier-chosen freshness. It keeps its stronger content: a bit-exact integer verdict, the toolchain matched to the seal, and agreement across three placements. The remaining gap to a TEE is device rooting, which is R3-2. The gap to stake-based systems is operator independence, which is R3-3.
Foreign code
Rust in
bootstrap/under the owner's standing rule (2026-10-06, translated: add the label yourself and do the foreign part). The new entry intools/policy/foreign-exceptions.txt(top block) coversbootstrap/Cargo.tomland the new integration test;service.rsandmain.rswere already listed. Every decision lives inspecs/verified/signed_receipt.t27. The Rust is I/O plumbing that mirrors it, and a test pins the constants to it.🤖 Generated with Claude Code