fix(operator): harden money-paths — revoke/resale reconcile, restart-safe gateway, durable redeem reservation#25
Merged
Merged
Conversation
…safe gateway, durable redeem reservation Critical audit of the consumption money-paths scored 6/10 (REQUEST_CHANGES) with 6 confirmed HIGH findings. Fix all six; each is backed by a real-system e2e (anvil + operator + stub), not a mock. - spend: authorize() never mirrored on-chain revocation/resale, so a revoked or leaked session key (or a resold lot) kept being served for free — settleSpend would revert, the operator just ate it. reconcile_revocations() now runs on each flush, dropping any channel the holder revoked (spendRevoked) or whose lot changed hands, fail-open on transient RPC. Exposure bounded to one flush interval. spend-rail.md corrected to describe the real mechanism. - gateway: per-channel acked was in-memory only; a restart re-signed cum=0, the operator 409'd stale_voucher, and the channel bricked. Journal acked to SURPLUS_GATEWAY_STATE (atomic) on every advance; seed from it on startup. - redeem: serve-auth reservation + served were journaled only after inference; a crash re-opened already-spent quota. persist_redeem() now runs after reserving the auth (before inference) and on release. Coverage: - spend-e2e: revoke on-chain -> flush drops the channel -> serve returns 401, no further billing. - gateway-multilot-e2e: streaming through the gateway (surplus event stripped) + a gateway restart that resumes from persisted acked and bills on. - CI: new money-e2e job runs spend-e2e + gateway-multilot-e2e (viem as a root devDependency so node resolves it); app job now runs the SOR unit checks (router.check.ts: 15 passed) instead of typecheck-only. Audit run + fix-plan persisted under .evolve/critical-audit/.
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.
Critical audit of the consumption money-paths (
/critical-audit and /harden) scored 6/10 — REQUEST_CHANGES across reviewers A/B/C, with 6 confirmed HIGH findings (0 CRITICAL). This PR fixes all six. Every fix is backed by a real-system e2e (anvil + operator + stub OpenAI), not a mock.HIGH fixes
spend.rsauthorize()never mirrored on-chain revocation/resale → a revoked/leaked session key or resold lot kept being served for free (settleSpend reverts, operator eats it)reconcile_revocations()on each flush drops revoked (spendRevoked) / resold channels; fail-open on transient RPCspend-e2e: revoke on-chain →flush.dropped>=1→ serve returns 401, no further billinggateway.rsackedin-memory only → restart re-signscum=0→ operator 409stale_voucher→ channel brickedackedtoSURPLUS_GATEWAY_STATE(atomic) on every advance; seed on startupgateway-multilot-e2e: kill + restart gateway → post-restart call succeeds, bills onredeem.rspersist_redeem()after reserving the auth (before inference) + on releasesettlement-e2eredemption serve/receipt path greengateway-multilot-e2e.mjsstream:truecall; assert SSE flows +surplusevent strippedci.ymlmoney-e2ejob runsspend-e2e+gateway-multilot-e2e(viem = root devDep)ci.ymlapp — testrunsrouter.check.ts(tsx)Verification (local, all green)
scripts/settlement-e2e.sh— fill → receipt redemption → default → attested + proven batches → attested redemption.scripts/spend-e2e.sh— one-sig key mint → buffered + streamed calls → on-chain billing → forged voucher refused → revocation drops the channel (401).scripts/gateway-multilot-e2e.sh— drain + failover → streaming through the gateway → restart resumes from persisted acked and bills on.cargo fmt --all --check,cargo build --features chain|mesh,cargo test --workspaceclean.Verdict
Initial REQUEST_CHANGES (6 HIGH) → after harden + re-verify APPROVE: 0 CRITICAL/HIGH remain. MEDIUM/LOW (stream task-leak, redeem assert_domain, Buy.tsx SOR leg-drop, Deploy 1-of-1 guard, …) are tracked in
.evolve/critical-audit/2026-06-14T01:20:02Z/as follow-ups — none blocks a 1-of-1 launch.Audit run + fix-plan persisted under
.evolve/critical-audit/.🤖 Generated with Claude Code