Repository navigation
feat(bep): carry the handle jti into the audit record (T68) - #2596
Conversation
The forwarder asks the redeemer for the handle's jti beside its verdict, and writes it into each decision record. min box audit shows it. The jti is empty when the request carries no handle or the handle does not parse.
…handle-jti-into-the-audit-record # Conflicts: # crates/bep/src/forward.rs
|
Important Review skippedBot user detected. To trigger a single review, invoke the
|
|
Approved: every review thread resolved at @norrietaylor resolved the last thread, which releases the approval this review had withheld. Nothing to do. |
There was a problem hiding this comment.
arch-review: PASS_WITH_CONDITIONS · 1 condition · the full ruling
The code does what Gatehouse §6.10 line 842 asks. Every decision about a sealed value records the handle's jti, and a store_handle_invalid refusal records it too. The gap is in spec 24. The task covers BEP-067, but BEP-067 is the mint and revocation record. BEP-039's field list and BEP-040's property do not name jti, but this PR widens the BEP-039 key-set test to include it. C1 amends the spec so that it records the field, or files an issue for the amendment.
Ruled at a8fc491 against gominimal/arch@109541a48c31 by claude-opus-5-5.
Only an admitted record's jti is verified, since decide admits only a verified handle. A refusal keeps the claimed jti so a forged handle still correlates.
|
Round 1 of 10 on the runtime's review findings, pushed as
Verify Review threads the coder judged:
A refused store member (store_handle_invalid) and a redeemed one both write an audit record that carries the handle's jti. The docs on Decision::jti and Record::jti now say that only an admitted record's jti is verified, and that a refused record's jti is the handle's claim. Notes from the agent: Revise round 1: this round changes only doc comments. The jti is not gated on handle.verified, because the task proof requires the jti on a store_handle_invalid refusal, and a bad signature is one cause of that refusal. redeem.rs:468 refuses every handle whose check fails, and check fails when the handle is not verified. So an admitted record's jti is always verified. |
There was a problem hiding this comment.
arch-review: PASS_WITH_CONDITIONS · 1 condition · the full ruling
The code conforms to Gatehouse §6.10 line 842. Each store-handle decision record carries the handle's jti, and a store_handle_invalid refusal also carries it. Spec 24 does not record the new field. BEP-039 owns the record shape, but its field list and its property at line 564 do not include jti. The task also covers BEP-067, which owns mint and revocation records. C1 amends the spec to agree with the design. The change can merge with C1 open.
Ruled at 9661e1a against gominimal/arch@109541a48c31 by claude-opus-5-5.
A refused handle's jti is an unverified claim, so a sender controls it. Debug formatting escapes control characters in the log line.
|
Round 2 of 10 on the runtime's review findings, pushed as
Verify Review threads the coder judged:
A refused store member (store_handle_invalid) and a redeemed one both write an audit record that carries the handle's jti, and min box audit shows it. The redeemer debug log now writes that jti escaped. Notes from the agent: This round changed one line in crates/bep/src/redeemer.rs: the debug log uses ?facts.jti. The two C1 threads ask for an amendment to spec 24 (BEP-039 and BEP-040). That spec file is not in this task's layers, so this round does not change it. A docs task or the spec owner must add jti to BEP-039 and BEP-040 with the Gatehouse section 6.10 line 842 citation. |
There was a problem hiding this comment.
arch-review: PASS_WITH_CONDITIONS · 1 condition · the full ruling
The code does what Gatehouse §6.10 line 842 asks. The audit record carries the handle's jti as its correlation id, on an admitted record and on a store_handle_invalid refusal. The last push only escapes the jti in a debug log, and that does not change the ruling. One item is open. Spec 24 BEP-039 lists the audit record's fields without jti, and the task names BEP-067, which is about mint and revocation records. Amend the spec as C1 says, or file an issue for it and link the issue from this PR.
Ruled at 4996b15 against gominimal/arch@109541a48c31 by claude-opus-5-5.
There was a problem hiding this comment.
minimal-review — approval withheld
Verdict COMMENT — APPROVE withheld: 6 unresolved threads — minimal-foundry[bot] crates/bep/src/redeemer.rs, minimal-arch[bot] crates/bep/src/audit.rs:171, minimal-arch[bot] crates/bep/src/audit.rs:830, minimal-foundry[bot] crates/bep/src/redeemer.rs, minimal-arch[bot] crates/bep/src/audit.rs:171, …. No findings.
Panel: 3 of 3 personas ran (correctness, security, supply-chain).
There was a problem hiding this comment.
minimal-review — approved
Verdict APPROVE — every review thread is resolved; @norrietaylor closed the last one. The review of 4996b152b375 withheld this approval on the threads open then. Posted as a comment: the App cannot approve its own pull request; the check and the label carry it.
There was a problem hiding this comment.
Own review at 4996b15: every sealed-value decision record carries the handle's jti, a mint or revocation record carries none, min box audit prints jti= only when the record has one and escapes it, and the debug line escapes an unverified claim. The spec gap (arch C1) is filed as #2600. The BEP-067 comment in box_audit.rs follows that issue's covers: move. No other findings.
Generated by Claude Code
There was a problem hiding this comment.
Babysitter approval at 4996b15: every merge gate passes at this head (arch PASS at 4996b15, zero open threads, every lane aggregator green). Squash title feat(bep): carry the handle jti into the audit record (T68) and the squashed message pass commitlint. Queued for squash merge.
Generated by Claude Code
|
/revise Round on #2596 after a merge-queue failure at 4996b15. No round is in flight. #2583 (T33) landed on main and added a
Generated by Claude Code |
…handle-jti-into-the-audit-record
The revocation helper that main added in #2583 builds a Decision without jti, which failed the merge-queue build with E0063.
|
Round 3 of 10 on a /revise note, pushed as
Verify A refused store member (store_handle_invalid) and a redeemed one both write an audit record that carries the handle's jti, and the branch now builds with main merged in. Notes from the agent: The merge of main (through a1e65c5) was already on the branch as 72e011d. The only Decision literal without jti was the revocation(box_id) test helper in crates/bep/src/audit.rs. It now sets jti: String::new() with the control.rs comment. redeemer.rs and main.rs add no Decision literal (main.rs only names Vec), so they needed no change. Nothing else changed. |
There was a problem hiding this comment.
arch-review: PASS_WITH_CONDITIONS · 1 condition · the full ruling
The merge from main and commit 95d6b6f4 do not change the ruling. The new commit sets an empty jti on a revocation test record. That is correct, because a revocation carries no handle. The code still records the handle's jti as the audit correlation id, as Gatehouse §6.10 line 842 says. C1 stays open as #2600: spec 24 BEP-039 must name jti, and covers: must move to BEP-039.
Ruled at 95d6b6f against gominimal/arch@109541a48c31 by claude-opus-5-5.
There was a problem hiding this comment.
Own review at 95d6b6f: a merge of main plus jti: String::new() on the revocation test record that #2583 added, which fixes the E0063 the merge queue hit. No other change since 4996b15.
Generated by Claude Code
There was a problem hiding this comment.
minimal-review — approved
Verdict APPROVE — every review thread is resolved; @norrietaylor closed the last one. The review of 95d6b6f4961b withheld this approval on the threads open then. Posted as a comment: the App cannot approve its own pull request; the check and the label carry it.
There was a problem hiding this comment.
Babysitter approval at 95d6b6f: every merge gate passes at this head (arch PASS at 95d6b6f, zero open threads, every lane aggregator green). Squash title feat(bep): carry the handle jti into the audit record (T68) and the squashed message pass commitlint. Queued for squash merge.
Generated by Claude Code
T68 — Carry the handle jti into the audit record
slice: S10
kind: task
covers: BEP-067
size: M
est: 110 code, 100 tests
executor: agent
difficulty: routine
model: standard
diagnostics:
min box audit <box>shows the handle'sjtion each store-handle record, empty when the handle does not parseobservability: the audit record carries
jtilayers:
- audit:
- crates/bep/src/audit.rs:
DecisionandRecordgainjti: String, empty when the handle does not parse- crates/bep/src/redeemer.rs:
facts()carrieshandle::Read::jtiinto the verdict (Gatehouse §6.10 line 842)- crates/bep/src/forward.rs:
Verdict::AdmitandVerdict::Refusecarry thejti, andrecordandaudit_refusalwrite it into theDecision(stale layers amended 2026-10-26 by the epic owner's rule)- crates/bep/src/control.rs: its
Decisionliteral sets an emptyjti- crates/bep/src/proxy.rs: its
Decisionliteral sets an emptyjti- crates/minimal/src/cmd/box_audit.rs:
min box auditshows thejti, and the test helper'sDecisionsets ittest: cargo nextest run -p bep a_store_handle_audit_record_carries_its_jti
produces: none
consumes: none
proof: A refused store member (
store_handle_invalid) and a redeemed one both write an audit record that carries the handle'sjti.depends on:
- blocked by #2540
Proof
A refused store member (store_handle_invalid) now writes an audit record that carries the handle's jti. A redeemed sign-in member does the same. The min/v1 line has a
jtifield, andmin box auditshowsjti=<value>at the end of the row when the record has one. A value that does not open, or a request with no sealed value, writes an empty jti.Notes from the agent: Deviation from the forward.rs layer note:
Verdict::Refusekeeps its shapeRefuse(&'static str), andVerdict::Admitgains no field. A field onRefusebreaks test code in crates/bep/src/revoke.rs and crates/bep/src/main.rs, which matchVerdict::Refuse(marker)andVerdict::Refuse("no_live_box"). The layers do not name those files. The jti travels instead through a new provided trait methodRedeemer::redeem_with_jti, which returns(Verdict, String). Its default gives an empty jti.BoxRedeemeroverrides it with the jti fromhandle::Read::jtithroughFacts, and itsredeemreturns the verdict alone.Flow::decidecallsredeem_with_jtiand passes the jti torecord. The task namesaudit_refusalunder forward.rs, but it is in proxy.rs. Its Decision literal sets an empty jti because it refuses before any sealed value is read.Record.jtihas#[serde(default)], somin box auditstill reads lines written before the field existed. The hash chain hashes the line bytes, so old lines still verify. Printed text:min box audittext rows addjti=<value>after the marker, only when the jti is not empty. The existing columns do not change. An earlier test,audit::tests::every_decision_appends_one_audit_record, pins the record's key set. I addedjtito it in a second commit. Extra runs:cargo nextest run -p bep(187 passed) andcargo nextest run -p minimal box_audit(8 passed). I did not runjust ciorjust clippy-strict.Tests
cargo nextest run -p bep a_store_handle_audit_record_carries_its_jtiVerify
min task run agent-verifyexited 101 under rustc 1.98.1, which the repository does not pin (1.99.0 in rust-toolchain.toml); the PR is not a draft on that alone — CI, which honours the pin, is the gate.Base
The base branch moved while the coder worked and was merged in before the tests ran. These files changed on BOTH sides since the branch point — read them first, because a rewrite from a stale reading can undo a merge without a conflict:
crates/bep/src/forward.rsResiduals
jti, and T68'scovers:moves to BEP-039 (arch C1).Closes #2576
Generated by Claude Code