Repository navigation
feat(testkit): offline settlement harness, restart durability, and fixture capture (B03) - #14
Merged
selezenart merged 2 commits intoSep 7, 2026
Conversation
Implements B03 offline closure for the Coder B lane. Live execution is not performed and is recorded as LIVE_NOT_RUN in docs/settlement/LIVE_EVIDENCE.md, which the packet explicitly permits. Harness (B03.2). Runs the whole adapter workflow against simulated providers with no network and no credential. Request identity is persisted before the provider call rather than after: the window between that write and the provider returning is exactly where a crash produces UNKNOWN, and the record is what makes it recoverable. Negative suite (B03.3). Every denial family asserts against a broadcast counter, not just the returned enum, because a denial that returned the right value while still broadcasting has not denied anything. Duplicate delivery, ten sequential retries, and ten parallel workers sharing durable state each produce exactly one broadcast. An ambiguous outcome does not grant a fresh submission right, so the dangerous retry after a possible payment cannot happen. Ambiguous scenarios deliberately increment the broadcast counter: counting them as non-broadcasts would understate exposure. Fixture capture (B03.5). Allowlists the fields needed to reproduce a decision so a new provider field cannot silently start appearing in committed fixtures, then redacts what survives and asserts no secrets at capture time. Fixes a redaction bug the round-trip test caught. The rule treating any 32-byte hex value as secret-shaped also matched transaction hashes, block hashes, event topics, ABI-encoded words, and payload fingerprints, so sanitizing a receipt destroyed the very evidence it was captured to preserve and the fixture no longer confirmed the settlement. Shape alone cannot separate a private key from a keccak hash, so the rule now applies only outside named hash-bearing fields; key material is still caught by field name regardless of shape, and a credential hidden inside a hash-bearing field is still redacted. Also adds the human-run provider setup guide, which keeps account creation, secret handling, policy mutation, and funding with a person and leaves only the read-only readiness check automatable.
An independent FreePi review of tree 5aacf17 returned VERDICT: FAIL with two blocking findings. Both were correct. 1. The setup guide told a human to run `npm run check` in packages/arc-adapter and called it "the readiness probe". It is not. That command runs lint, typecheck, and unit tests against stubbed endpoints; it proves the probe's logic and says nothing about whether a particular operator's endpoint, chain, and token are correct. A human following the guide would have believed their setup was verified when nothing had contacted it. Adds a real read-only probe. createViemProbe implements the RpcProbe interface over viem, and `npm run probe` loads configuration from the environment, asks the configured endpoint which chain it is actually on, checks the USDC address holds bytecode, and prints a per-check report. It cannot sign, send, or mutate, and it prints no credential. Section 7 now points at it and explains why `npm run check` is not a substitute. 2. AttemptLog was in-memory, so B03.2's requirement to persist request identity in ignored test runtime state before submission was not met, and the at-most-once claims were an artifact of a shared process rather than a demonstration of durability. Restart is a boundary the failure-injection skill requires be exercised. Adds FileAttemptStore, writing through to JSON under an ignored tmp/ directory, and moves the store behind an AttemptStore interface. Writes are immediate: buffering would reopen the crash window the store exists to close. New restart tests build a fresh store from the same file, as a restarted process would, and prove a restarted worker is refused a second submission right, including after an outcome that was never learned, and that ten restarted workers still broadcast exactly once.
Deploying with
|
| Status | Name | Latest Commit | Updated (UTC) |
|---|---|---|---|
| ❌ Deployment failed View logs |
oneshot | b6fcd25 | Sep 07 2026, 02:49 PM |
Merged
7 of 10 tasks
selezenart
merged commit Sep 7, 2026
63af09b
into
milestone/b02-request-policy-receipt
3 of 4 checks passed
6 of 9 tasks
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.
Summary
Implements B03 — offline-complete and live-ready settlement harness for the
Coder B lane.
Live status is
LIVE_NOT_RUN: no Privy application, wallet, policy, orfunded testnet account has been provisioned, because provisioning is a human
action. The packet explicitly closes on its offline criteria; live execution is
tracked as Gate P4 evidence.
Stacked on B02 (PR #12), which is stacked on B01 (PR #11). Review those
first.
Scope and acceptance criteria
The change is limited to the stated milestone or issue.
Acceptance criteria are listed and satisfied.
No unrelated cleanup is included.
B03.1 human setup guide —
docs/settlement/PROVIDER_SETUP.md. Accountcreation, secret handling, policy attachment, and funding stay with a person;
only the read-only probe is automatable.
B03.2 standalone harness — accepts a frozen intent, persists request
identity to durable state before the provider call, emits only sanitized
evidence.
B03.3 policy negative suite — every denial family asserted against a
deterministic broadcast counter.
B03.4 allowed settlement — offline path only.
LIVE_NOT_RUN.B03.5 live-to-fixture conversion — allowlisted capture, redaction, and a
round-trip proving fixtures reproduce the original verifier result.
Product and security invariants
Invariant notes:
Tenant isolation and sponsor-control rows are not applicable: no durable
product state or tenant boundary exists in this diff. What is proven here:
counter rather than the returned enum. A denial that returned the right value
while still broadcasting has not denied anything.
ten parallel workers sharing durable state, and ten restarted workers.
outcome that was never learned. That retry is the double payment the product
exists to prevent.
Counting them as non-broadcasts would understate exposure.
Validation
Independent review evidence
Two FreePi reviews,
free-pi-cli0.2.19 onglm-5.3-flash.First review — tree
5aacf1713f4ea260cdab0ba5843b1b7e281cfce5—VERDICT: FAIL.Two blocking findings, both correct:
PROVIDER_SETUP.md§7 told a human to runnpm run checkand called it thereadiness probe. It is not: that runs unit tests against stubs. A human
following the guide would have believed their setup was verified when
nothing had contacted it.
AttemptLogwas in-memory, so B03.2's "persist identity before submission"was unmet and the at-most-once claims were an artifact of a shared process
rather than a demonstration of durability.
Fixes: added
createViemProbeand annpm run probecommand that actuallycontacts the configured endpoint read-only; added
FileAttemptStorewritingthrough to JSON under an ignored
tmp/directory, with restart tests thatbuild a fresh store from the same file as a restarted process would.
Second review — tree
9927eb51246f1c69e49f5cdc60677b0063a28993—RECHECK_PASS,no blocking findings. Asked specifically to judge whether the fixes were
genuine rather than papered over, whether the probe can mutate or leak, and
whether the restart tests prove durability or merely re-read a file.
Note on evidence quality: the reviewer's literal
VERDICT:line was lost toterminal viewport truncation in the second run; the captured evidence is the
terminal
RECHECK_PASStoken and an empty blocking-findings section.Risk and rollback
ESLint and TypeScriptjob finds no root
pnpm-lock.yamland skips. All 263 tests are local only.should be dropped when Coder A scaffolds the pnpm workspace root.
shape is modelled from documentation and has never been exercised against a
live tenant, and Arc receipt shapes are assumed. Per the
sponsor-qualificationskill, no Privy or Arc claim may be made fromfixtures alone; both remain
NOT VERIFIEDuntilLIVE_EVIDENCE.mdrecords asanitized live transaction.
FileAttemptStoreis a test stand-in for the PostgreSQL state Coder A owns,not a production store.
Rollback: additive packages and docs on a short-lived branch. Revert or close.
Human merge