feat(gate): bind plan-task completion to gate-issued receipts - #70
Merged
Conversation
EXECUTE_PLAN task completion accepted any non-empty checkpoint.receiptIds, so a model-invented string satisfied the rule without a gate ever having passed. Per-task receipts are now minted only by base2's own validation/reviewer gate pass, and update_plan_status verifies the cited ID against gate state. Receipts carry an evidence kind so a gate cycle that produced no reviewable diff is still completable without the receipt overstating what it attests: reviewed-diff, unreviewed-scope, and no-diff. Every kind holds the same fingerprint invariant so verification is uniform, and the ID always derives from the fingerprint base2 computed itself rather than a reviewer-reported one. A non-attestable fingerprint mints nothing. A receipt also stops authorizing completion once the work it covers changes: content verification recomputes each invariant at turn start and again immediately before the mint, and change supersession drops receipts whose files intersect a recorded change plus every non-reviewed-diff receipt. At most one receipt is live per task, and because supersession changes the ID, the live ID is re-printed on every gate pass and surfaced in the pinned active-work block. Closes two fail-open cases in that evidence path: a present-but-non-array planTaskGateReceipts is normalized at hydration and read through one guarded accessor instead of throwing a TypeError inside handleSteps, and the update_plan_status reader treats such a ledger as verification-active-with-no-evidence instead of falling back to the legacy rule. Pointer-only update_plan_status results are recognized via an opt-in success pattern, so releasing a task no longer leaves a stale claim minting receipts for it, while the shared failure-word veto still rejects an unapplied call. The persisted gate-state additions and the new optional gateIssuedReceipts parameter are additive, so older serialized state and existing callers keep their behavior. Validation: agents unit and e2e 1145 pass / 0 fail; plan-execution-state plus update-plan-status handler tests 44 pass / 0 fail; configured hooks green (script:typecheck, typecheck-agents, typecheck-agent-runtime); reviewer gate LOOKS_GOOD for the full 8-file set.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
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.
EXECUTE_PLAN task completion accepted any non-empty checkpoint.receiptIds, so a model-invented string satisfied the rule without a gate ever having passed. Per-task receipts are now minted only by base2's own validation/reviewer gate pass, and update_plan_status verifies the cited ID against gate state.
Receipts carry an evidence kind so a gate cycle that produced no reviewable diff is still completable without the receipt overstating what it attests: reviewed-diff, unreviewed-scope, and no-diff. Every kind holds the same fingerprint invariant so verification is uniform, and the ID always derives from the fingerprint base2 computed itself rather than a reviewer-reported one. A non-attestable fingerprint mints nothing.
A receipt also stops authorizing completion once the work it covers changes: content verification recomputes each invariant at turn start and again immediately before the mint, and change supersession drops receipts whose files intersect a recorded change plus every non-reviewed-diff receipt. At most one receipt is live per task, and because supersession changes the ID, the live ID is re-printed on every gate pass and surfaced in the pinned active-work block.
Closes two fail-open cases in that evidence path: a present-but-non-array planTaskGateReceipts is normalized at hydration and read through one guarded accessor instead of throwing a TypeError inside handleSteps, and the update_plan_status reader treats such a ledger as verification-active-with-no-evidence instead of falling back to the legacy rule. Pointer-only update_plan_status results are recognized via an opt-in success pattern, so releasing a task no longer leaves a stale claim minting receipts for it, while the shared failure-word veto still rejects an unapplied call.
The persisted gate-state additions and the new optional gateIssuedReceipts parameter are additive, so older serialized state and existing callers keep their behavior. Validation: agents unit and e2e 1145 pass / 0 fail; plan-execution-state plus update-plan-status handler tests 44 pass / 0 fail; configured hooks green (script:typecheck, typecheck-agents, typecheck-agent-runtime); reviewer gate LOOKS_GOOD for the full 8-file set.
This change is