Skip to content

fix: close what the review of idempotency, snapshots and personal data found - #220

Merged
benatespina merged 2 commits into
mainfrom
fix/runtime-review
Oct 31, 2026
Merged

benatespina merged 2 commits into
mainfrom
fix/runtime-review

Conversation

@benatespina

Copy link
Copy Markdown
Member

A review of #212, #211, #213 and #219 together, before they ship in 0.3.0.

  • No forget over HTTP. createWorker no longer answers POST /forget/<personId>: it has no authentication, and every Worker built on it, the Deploy to Cloudflare template included, would let anyone forget anyone for good. Apps call forget through connect behind their own authentication; the docs say so.
  • A key per command in React Router. The middleware gives each command idempotencyKeyFor(header, commandName) instead of the raw header, so an action that dispatches two commands no longer conflicts on the second after the first committed.
  • Fingerprints. An idempotency key now also names the dispatch's delay (a scheduled command and an immediate one never share a key), and maps, sets and bigints are told apart by what they hold instead of collapsing to {} or throwing.
  • Persons read in the clear. A person named with a null fingerprint needs no key for a snapshot or a remembered rejection to be written; before, a stream with a marked field stored in the clear was never snapshotted again, silently.
  • Snapshots only move forward. A put older than the stored snapshot of the same fingerprint is ignored, in every adapter.
  • PostgreSQL indexes persons (GIN, jsonb_path_ops) on snapshots and idempotency keys, so forget finds its rows without a full scan.
  • Docs. What forget cannot reach (scheduled payloads, dead letters, logs), the delay in the conflict rules, and a link from idempotent commands to delivery guarantees. The three pending changesets describe the result.

pnpm check passes (PostgreSQL included). Stryker on the files touched: 100 % on fingerprint.ts, held-keys.ts (both), the SQLite and memory stores and idempotency-key.ts; the survivors left in pipeline.ts, schema.ts, snapshot-store.ts (PostgreSQL) and worker.ts are on lines this PR does not change.

…a found

- createWorker no longer forgets anyone over HTTP: an irreversible operation has no place on an
  endpoint without authentication; apps call `forget` through `connect` behind their own.
- The React Router host derives each command's key from the Idempotency-Key header and the
  command's name, so an action that dispatches two commands no longer conflicts on the second.
- An idempotency key now also names the dispatch's delay, and fingerprints tell maps, sets and
  bigints apart instead of collapsing them or throwing.
- A person whose fields were read in the clear needs no key for a snapshot or a remembered
  rejection to be written, so such streams are snapshotted again.
- A snapshot never replaces a newer one of the same fingerprint.
- PostgreSQL indexes `persons` so forgetting a person finds their rows without a full scan.
- The personal-data guide says what forget cannot reach: scheduled payloads, dead letters, logs.
@benatespina
benatespina merged commit f2bece2 into main Oct 31, 2026
8 checks passed
@benatespina
benatespina deleted the fix/runtime-review branch October 31, 2026 11:11
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