Skip to content

feat: opt-in attested execution receipts (devnet)#219

Merged
nullxnothing merged 5 commits into
mainfrom
growth/loop6-receipts
Jul 4, 2026
Merged

feat: opt-in attested execution receipts (devnet)#219
nullxnothing merged 5 commits into
mainfrom
growth/loop6-receipts

Conversation

@nullxnothing

Copy link
Copy Markdown
Owner

Turns the proven registry-receipt spike into a real, off-by-default feature: DAEMON can emit a verifiable hash of an execution record on-chain, so an agent's track record is checkable instead of claimed.

  • Opt-in via receipts.enabled (default false). On-chain payload is only DAEMON-RECEIPT v1 sha256= - never file contents, prompts, keys, wallet addresses, or PII. The receipts ledger stores hash/source/action/cluster/verdict/signatures only.
  • Devnet-only, enforced twice: the service gate (enabled AND cluster devnet AND signer present) and a hard assert inside the emitter itself (anchorMemo refuses any cluster but devnet, with a devnet-locked RPC endpoint), so off-devnet emission is impossible even if the gate is bypassed. Mainnet emission is a clearly-scoped follow-up, wired but a no-op.
  • Dedicated receipt signer keypair, never the trading vault. No signer = clean no-op.
  • Fire-and-forget: emitReceiptSafe defers all work to a setImmediate tick and swallows exceptions, so a receipt never blocks or breaks an ARIA tool or an autopilot tick. Ledger growth is capped (keep newest 1000).
  • Hooks after a successful ARIA write/sensitive tool and after a landed autopilot action.

Suite 1063 to 1142 (+79 across the slice, none skipped). Typecheck, build, lint:styles green. Independent review: one blocker (ungated emit boundary) + two findings, all fixed and re-verified. No live tx (devnet faucet dry); the memo path builds and signs against a live devnet blockhash.

nullxnothing and others added 5 commits July 3, 2026 20:07
Adds a ReceiptService that hashes a completed execution record and anchors
only the SHA-256 on-chain via an SPL Memo, behind a settings toggle that is
off by default. On-chain payload is the content hash plus a "DAEMON-RECEIPT v1"
marker — never file contents, keys, prompts, or PII.

- receiptBuilder: pure canonical JSON + deterministic content hash
- receiptChain: memo emitter signed by a dedicated receipt key (never the
  trading vault); no signer provisioned = no-op
- ReceiptService: enabled + devnet-only + signer gate; fire-and-forget so a
  receipt failure can never block or reverse the action that produced it
- receipts ledger table (schema V58) for the "receipts emitted" surface
- hooks after a successful ARIA write/sensitive tool and a landed autopilot buy
- IPC to read/set the toggle and read the ledger

Mainnet emission is deliberately gated off and left as a follow-up; this slice
scopes real emission to devnet. Chain layer is injectable so tests never make a
live call.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
anchorMemo trusted a caller-supplied cluster to pick the RPC endpoint, so a
future or mistaken caller could have landed a receipt tx on mainnet if the
orchestrator gate were bypassed. Hard-assert the cluster is devnet before
loading a signer or opening a connection, and derive the endpoint from a
devnet-locked constant rather than caller input. Off-devnet emission is now
impossible at this layer regardless of shouldEmit.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The receipts table only grew — every emission inserted and nothing pruned.
Since the ledger just feeds a count and a recent list, keep the newest 1000
rows and prune older ones opportunistically on insert. Adds a real-SQLite
test asserting the keep-newest bound.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
emitReceiptSafe did a synchronous SQLite settings SELECT inline before
returning, so a receipt check could delay the ARIA tool call or autopilot
tick that triggered it. Defer everything — settings read, gate, build, hash,
anchor, ledger — to a setImmediate tick so the hook returns to the caller at
once. Still fully exception-proof: nothing can flip the underlying action to
error. Tests assert no settings/DB access happens on the synchronous path.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@nullxnothing nullxnothing enabled auto-merge (squash) July 4, 2026 02:29
@nullxnothing nullxnothing merged commit a05bb4d into main Jul 4, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant