# Reconcile duplicate, late and missing callbacks with a local ledger

Keep one task identity while reconciling repeated or out-of-order delivery. This is an offline integration exercise; the site does not currently promise customer Webhooks.

This complete kit uses Node standard-library modules only. No media tool installation is required.

Run from this directory and select a NEW output directory. Existing output directories are refused. On a memory-managed workstation, put its local serialization wrapper before the Node command. No provider credentials or off-device fixture requests are used.

```sh
node run-recipe.mjs --out ./my-run
```

Recorded execution: 10 checks passed, including 1 expected rejections. Node v24.18.0. No FFmpeg subprocess.

Preparation

- Download the complete kit and use Node.js. The recorded run used Node v24.18.0 with only its built-in HTTP, filesystem and crypto modules.
- Read fixture.json: local-A receives a success event twice and then a late processing event; local-B receives no callback and is recovered by one local status request.
- Choose a fresh output directory. The server binds an ephemeral port on 127.0.0.1, accepts only the two fixture task IDs and closes in finally. No provider credentials are used.

## 01. Bind callbacks to a known task

Run the command from the unzipped kit. Before accepting an event, the receiver checks the task ID, event ID and its deliberately small processing/succeeded state vocabulary. The fixture rejects unknown tasks and an invented state with HTTP 400. These validation rules are local examples, not a provider payload specification.

## 02. Apply each event once

Read ledger.json after the replay. evt-1 changes local-A to succeeded; replaying the same event ID is recorded as duplicate. The event set is a fixture store in memory. A deployed receiver would need durable event uniqueness and an atomic state update appropriate to its own database.

## 03. Protect the completed state

The distinct evt-2 arrives late with processing. Its lower state rank is logged as stale, leaving local-A succeeded. This two-state policy demonstrates a terminal guard; it does not define cancellation, failure, retry or conflicting-terminal rules for a real API.

## 04. Reconcile the absent callback

local-B remains processing until GET /status/local-B returns its matching task ID and succeeded state. Update the same ledger entry and verify one poll, zero /generate requests and a closed local server. The negative receipt also checks a poll result bound to the wrong task.

Acceptance

- All ten named checks pass and the two executing script hashes match before and after the run.
- The initial terminal event is applied and its exact event ID replay is marked duplicate.
- The late processing event is marked stale and local-A remains succeeded.
- An unknown task and an invented state both return HTTP 400.
- local-B is pending before reconciliation and succeeded after one task-bound local poll.
- ledger.json reports zero generation requests and the loopback server is closed.

Troubleshooting

The same delivery changes the task twice. Use the event ID as the uniqueness key and rerun the exact evt-1 replay; the expected second action is duplicate.

A completed task goes back to processing. Change only the transition guard and replay evt-2 after success. The state must remain succeeded.

A task never receives a callback. Enable one task-bound reconciliation read for that pending identity. Check its returned task ID before applying state; do not submit another generation.

Public receipt copies normalize only local checkout paths and include publicPathNormalization with the original receipt SHA-256; raw originals are retained outside public assets. The actual receipts are under executed/. failure-receipt.json lists expected negative cases, not failed-suite assertions. Original tiny fixtures are generated again into your new output directory; shipped executed inputs and outputs let you inspect the recorded run. Temporary raw buffers and local HTTP servers are cleaned in finally.

checksums.json records every distributed file except itself and the archive, avoiding self-reference. The ZIP includes that same checksum list. Recompute hashes after download; comparison requires trusting the expected list. execution-receipt.json records executed script hashes before and after the run. The complete kit archive is also bound by the publishing catalog asset inventory.

Keep the replay ledger and receipts as evidence of this local reducer. Adapting it to a real service requires that service’s documented callback support, verification rules and durable storage; this kit makes no customer Webhook commitment.

Sources read on 2026-10-14

- Node.js HTTP API: server lifecycle and requests: https://nodejs.org/api/http.html
- Node.js crypto API: SHA-256 hashing: https://nodejs.org/api/crypto.html
