Without Once: 2 effects
Refund commits → acknowledgement lost → caller restarts → blind retry → another refund.
Local refund proof · no account · no money movement
The provider can succeed before its response reaches you. Blind retry can send a second refund. Once keeps that uncertainty and blocks another write until authoritative truth confirms the original result.
Refund commits → acknowledgement lost → caller restarts → blind retry → another refund.
Refund commits → UNKNOWN → restarted retry blocked → read-only reconciliation → original receipt recovered.
One command runs the same controlled fixture:
npx --yes --package=@once-agent/sdk@0.1.25 once proveOr download the inspectable standalone source into your own directory:
Node.js 24.15+. An independent local HTTP provider keeps a separate effect journal. No cloud account, keys or payment account.
npm install @once-agent/sdk@0.1.25
curl -fsSLo prove.mjs https://onceexec.com/first10/prove.mjs
node prove.mjs
PowerShell download: Invoke-WebRequest https://onceexec.com/first10/prove.mjs -OutFile prove.mjs.
Prefer a checkout? See the complete source and instructions. The ticket quickstart provides another installed-SDK example.
WITHOUT ONCE: 2 provider writes
CONFIRMED: first execution, restart replay, 1 provider write
RETRY BLOCKED — ORIGINAL OUTCOME UNKNOWN
Changed £50 → £80: CONFLICT, 0 additional writes
UNKNOWN → CONFIRMED: recovered refund_1
PASS
Actual output also prints the evidence directory and measured runtime. Each stage independently reads provider truth and compares its journal; a failing assertion exits nonzero. The proof includes unavailable truth and NOT_FOUND remaining blocked.
Fixture PASS proves this controlled provider only. It does not certify your operation, a real financial provider, or power-loss durability. Every caller stage starts a fresh process. Inspect the runnable source.
If the provider's key covers the complete operation, retry horizon and effect inputs, use it. If a database unique constraint completely solves the operation, use it. If repetition is harmless, you probably do not need Once.
Once is relevant when the caller cannot safely establish whether another dispatch creates another consequence. Keep native idempotency; Once does not make arbitrary external effects atomic or replace your framework, queue or database.
Choose a durable, tenant-scoped refund-intent ID. Multiple legitimate partial refunds need distinct intent IDs; a transport request ID is not the business operation. Review all effect inputs and provider/account authority explicitly.
import { wrapTool } from "@once-agent/sdk";
const safeRefund = wrapTool(refundCustomer, {
operationId: x => `${x.tenantId}:refund:${x.refundIntentId}`,
effect: x => ({ tool: "payments:reviewed-account:refund", args: x }),
statePath: "./durable/operations.sqlite",
reconcile: lookupAuthoritativeRefund,
});
Your callback and lookup need reviewed provider semantics. Bind every effect field; exclude Authorization credentials. Route every write through the wrapper. Internal callback retries remain outside the boundary. Persistent shared SQLite covers one machine only.
UNKNOWN is protection. Retain the same identity and state. Reconcile authoritative read-only truth; unavailable truth stays blocked. Do not invent a new ID or bypass protection to force progress. Absence alone does not permit local redispatch.
Apply the complete wrapper pattern