diff --git a/docs/adr/0119-plugin-reachable-transactions-and-honest-atomic-batch.md b/docs/adr/0119-plugin-reachable-transactions-and-honest-atomic-batch.md index 94d66f674d2..bb67ffbae5f 100644 --- a/docs/adr/0119-plugin-reachable-transactions-and-honest-atomic-batch.md +++ b/docs/adr/0119-plugin-reachable-transactions-and-honest-atomic-batch.md @@ -115,7 +115,7 @@ Mechanical removal is #4618, following the `spec-property-retirement` playbook's `batchData` honours `options.atomic === true` by running the whole batch inside one `engine.transaction()`. The first failure aborts and rolls back every prior write, and — the part that makes it honest — **the response says so**: `succeeded: 0`, and every row reports failure, with rows before the failure marked `ROLLED_BACK:`, the failing row carrying its causal error, and rows never reached marked `NOT_ATTEMPTED:`. A response claiming `success: true` for a row that was rolled back is the bug, not merely a missing transaction. -Where the runtime **cannot** roll back — no `transaction()` on the engine, or a default driver without `beginTransaction` — an atomic request is **refused** with `501 NOT_IMPLEMENTED` rather than silently degrading to best-effort. This follows the cross-object `/batch` route's existing precedent (`packages/rest/src/rest-server.ts#NOT_IMPLEMENTED`) and uses the standard error catalog, so no new code enters the ADR-0112 ledger. Refusing is the whole point: silent degradation is how the flag came to lie in the first place, and a caller that asked for atomicity is exactly the caller who must not receive best-effort without being told. +Where the runtime **cannot** roll back — no `transaction()` on the engine, or a default driver without `beginTransaction` — an atomic request is **refused** with `501 NOT_IMPLEMENTED` rather than silently degrading to best-effort. This follows the cross-object `/batch` route's existing precedent (`packages/rest/src/batch-routes.ts#NOT_IMPLEMENTED`) and uses the standard error catalog, so no new code enters the ADR-0112 ledger. Refusing is the whole point: silent degradation is how the flag came to lie in the first place, and a caller that asked for atomicity is exactly the caller who must not receive best-effort without being told. `atomic` takes precedence over `continueOnError` — whose own description already scopes it to `atomic=false`, making this precedence documented rather than new. In atomic mode the upsert path's defensive `catch { insert }` fallback rethrows instead of retrying, because inside an aborted transaction the fallback insert can only fail with a secondary error that masks the real cause.