feat(kernel): ship the recurring Gmail draft delegation proof (#130) - #178
Conversation
Cover action catalog and scoped admission, approval and owner-review pipelines, miner runtime and artifact stores, plus regression coverage and OpenSpec bookkeeping.
Replace fabricated capability and census test names with the existing owner-path tests, and close the verified process and evidence checklist rows.
Complete the first vertical reusable-delegation proof: counterparty erasure becomes a store-level admission predicate consulted inside the reservation transaction and swept across every persisted standing rule; repeated-approval evidence becomes typed and decision-event-deduplicated; a miner proposal reaches owner review only through the shared evaluation core carrying an immutable binding re-verified inside the activation transaction, which mints a fresh owner grant instead of reusing the miner's; lifecycle refusals surface as refusals; and email.send joins the catalog's non-delegable data. Record D-167..D-172. Address a pre-merge adversarial review pass: - add catalog_email_send_is_non_delegable and unresolved_counterparty_falls_back_via_action_api, both mutation-verified - correct six fabricated/renamed test citations in the reachability census - mark the scoped reservation transactional recheck UNPROVEN rather than crediting the pre-transaction check's test twice (D-172) - restore a dropped concurrency clause and dropped Test anchors in the MODIFIED spec bodies, and drop a scenario duplicated from an untouched requirement - refresh drifted api/actions.rs citations and disclose the activation-grant and lifecycle-refusal work in the proposal
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
|
Important Review skippedToo many files! This PR contains 160 files, which is 60 over the limit of 100. To get a review, reduce the PR to 100 files or fewer by splitting it into smaller PRs or changing its base branch. Upgrade to a paid plan to raise the limit. This review couldn't start because sufficient usage credits or metered capacity aren't available. Add credits or update usage-based reviews in the billing tab, then retry. ⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (160)
You can disable this status message by setting the Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Closes #130.
The first complete vertical delegation proof: a recurring Gmail draft now runs end to end in the runtime — propose → evaluate → review → activate → scope-match → create one real draft → receipt → controls — and falls back before effect on erasure, drift, budget, pause, expiry, revocation, an unresolved counterparty, or a fenced retry.
What shipped
erased_counterpartiesmarker is read before admission (api/scoped_admission.rs:222,api/actions.rs:554) and again inside the sameBEGIN IMMEDIATEthat selects, reserves, and claims a fired token (store/standing_rules_scoped.rs:137-144,store/standing_rules_fired_token.rs:82-96). The erasure transaction sweeps generic reviewed-scopeCounterpartyvalues across every persisted standing rule, including owner-review-created rows with nolearned_artifactsprovenance. A digest check cannot substitute: erasure leaves the reviewed-scope digest unchanged.DelegationEvidence::repeated_approvalsreplaces the raw(artifact_id, action_id)audit-row count, grouped by complete context-class digest and deduplicated ondecision_event_id. The old count is removed, not left beside it.artifact.proposeevaluation core and only on a passing receipt; the review carries anevaluation_bindingre-verified inside the activation transaction (store/activation.rs:199-235), not in a preflight-only check.email.sendjoined the catalog's non-delegable data, characterized at all three readers.Review
Two independent adversarial reviewers ran over the diff plus the OpenSpec artifacts before this PR.
Correctness/security lens —
APPROVE_WITH_NITS. The one merge-blocking class (activation-transaction guarantees) is clean on all four sub-questions: the empty-verdict-set hole inreject_stale_eval_verdictsis unreachable because presence and exact identity are strictly upstream in both the preflight and the transaction; a non-passbound verdict refuses at both layers; comparison is against the review's immutable binding rather than its own bytes; and the earlytx.commit()carries only the refusal audit. The fresh owner grant is genuinely composed with no fallback to the source grant. The erasure read is inside the reservation transaction, and the marker insert and the sweep are the same transaction, so there is no window.claim_pending_draft_writehas no TOCTOU (BEGIN IMMEDIATEtakes the write lock before the existence check). Its four findings are allFOLLOW-UP-ISSUEand are filed: #173, #174, #175, #176.Simplicity/scope/spec-fidelity lens —
REQUEST_CHANGES, now addressed. Every finding was verified against source and fixed in this PR:catalog_email_send_is_non_delegable(droppingemail.sendfromwith_non_delegablemoves the refusal to the policy-deny axis and the test fails) andunresolved_counterparty_falls_back_via_action_api(deleting the guard still yieldsApprovalRequired, so the test binds on the guard's own audit reason — a reason-free assertion survives and is not evidence). Four were renamed or fabricated citations, corrected to the existing tests.standing-rulesMODIFIED body, droppedTest:anchors were restored to the retainedreflection-minerscenario, and a scenario duplicated from an untouched sibling requirement was removed from theresponsibility-contractdelta — canon must not carry the same normative statement twice.standing-rulesrequirement "Pending Gmail writes MUST fence retries before budget reservation" (predicate: a matching pending row, matchingstore/pending_draft.rs), anddigest-bound-draft-approvalnow cross-references it instead of asserting a narrowerDeliveryUnknownpredicate. Scenario count unchanged at 18.api/actions.rscitations were re-derived,design.md's module path forverify_miner_evaluation_bindingwas corrected, D-167 and D-168 were corrected where they overstated a single call site and misdescribed the removed predicate, and the activation-grant and lifecycle-refusal work is now disclosed inproposal.md.Deliberately open task rows
Three rows in
tasks.mdland open and disclosed:email.create_draftaction-API regression proving it never falls back to action-keyedconsult_standing_rule_gate— no named test exists; the production guard is present but this control is unproven.Verification
./scripts/check.sh ship-recurring-gmail-draft-proof→All checks passed.(fmt, clippy-D warnings, workspace tests, file sizes, claims register, OMP ceremony, strict OpenSpec validation).The three named proof tests pass by exact name:
scoped_allow_returns_responsibility_receipt(positive: one real draft against the mocked Gmail endpoint plus a responsibility receipt rather than an approval prompt),erased_counterparty_scoped_admission_falls_back_to_owner_approval(fallback),pending_delivery_unknown_fences_scoped_retry_before_reservation(control).CI fails in seconds with a GitHub Actions billing/spending-limit error; that is not a code signal. Local gates plus the two reviewer passes are the effective gate.
Summary by cubic
Ships the first end-to-end reusable Gmail draft delegation path and hardens admission, activation, and lifecycle handling. Previously, reusable drafts lacked store-level erasure checks, evaluation-binding enforcement, and retry fencing; now the runtime admits, scopes, drafts, and falls back with durable receipts and fences.
artifact.proposeevaluation; activation re-verifies the immutable binding and mints a fresh owner grant instead of inheriting the miner’s.pause/resumereturn typed outcomes and concurrent lifecycle intents write a single transition audit.email.sendas non-delegable; the propose path refuses it before any review surface exists.email.create_draftadds unresolved/erased-counterparty fallbacks and returns aResponsibilityReceipton allow; draft writes use a stable request fingerprint to fence retries, treat timeouts as delivery-unknown with a durable pending row, fence subsequent identical requests before reservation, and notify the owner.Rollout and review
pending_draft_writes.request_fingerprint(no backfill). Legacy pending rows do not fence; only new writes are fenced.store/activation.rs(transactional evaluation-binding recheck and fresh grant),api/scoped_admission.rs(unresolved/erased-counterparty checks and admission receipt), andstore/pending_draft.rs(fingerprint and retry fence).action_catalog.rsnow treatsemail.sendas non-delegable.Written for commit 6ac963a. Summary will update on new commits.