From 6102e89921a1d444d258f7d4797aacf46415c049 Mon Sep 17 00:00:00 2001 From: Sean Silvius Date: Sun, 2 Aug 2026 22:13:25 -0700 Subject: [PATCH 1/2] spec: make the atomic obligation unconditional and record its asymmetry S10.1 item 5 read "Honor `atomic: true` on batch requests when not rejected." The qualifier gated a MUST on a rejection mechanism the spec never defines: S7 registers no code meaning "atomicity unavailable," and S4.2's only rejection clause is statement-count overflow to 413. Drop the qualifier so the conformance section agrees with S4.2's already-unqualified MUST. Both reference servers already honor atomic, so this codifies shipped behavior and neither becomes non-conforming: examples/cloudflare-worker-to-d1/src/index.ts:92 (db.batch) and examples/cloudflare-durable-object/src/index.ts:124 (ctx.storage.transactionSync). Also adds a clearly-marked non-normative note near S4.2 stating the v0.1 contract honestly: atomic: true cannot be declined conformingly and cannot be verified by the client, and the candidate shapes for a future version live in issue #13. Closes #12 Closes #13 Co-Authored-By: Claude Fable 5 --- SPEC.md | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/SPEC.md b/SPEC.md index e115dab..50665c7 100644 --- a/SPEC.md +++ b/SPEC.md @@ -65,6 +65,29 @@ A request body MUST be a JSON object containing **either** a `sql` field (single Servers MAY reject batches that exceed a server-defined statement count with HTTP status `413` and `error.code` of `payload_too_large`. +> **Non-normative note (not part of the v0.1 contract).** The `atomic` obligation above is +> one-directional, and v0.1 states that asymmetry deliberately rather than by oversight. +> +> There is no conforming way to decline. The obligation on `atomic: true` is unqualified +> here and in section 10.1, and section 7 registers no code meaning "atomicity unavailable." +> A server that cannot execute batches transactionally is simply non-conforming for batch in +> v0.1. Even if such a server declined with a `vendor:` code, the signal would not travel: +> section 7 directs clients to treat unknown codes as the closest registered code by HTTP +> status family, which collapses the decline into ordinary `bad_request` / `sql_error` +> semantics. +> +> There is also no way to confirm. Section 6.2's batch success envelope carries no atomicity +> field and section 9 defines no atomicity header, so a `200` is shape-identical whether or +> not the batch ran in a transaction. A client that sent `atomic: true` cannot verify the +> obligation was met, and a client whose correctness would depend on that confirmation is +> better designed as if no transaction exists. +> +> Three candidate shapes for closing the gap in a future version — a registered +> `not_supported` code, an `atomic` echo field in the section 6.2 envelope, and capability +> advertisement — are recorded in +> [issue #13](https://github.com/rafters-studio/http-sql/issues/13) and are deliberately out +> of scope for v0.1. + ## 5. Parameter types Positional parameters use JSON values. The mapping to SQL types is: @@ -203,7 +226,7 @@ A v0.1 conforming server MUST: 2. Accept both single-statement (section 4.1) and batch (section 4.2) request shapes. 3. Return the success envelopes defined in section 6 for successful execution. 4. Return the error envelope defined in section 7 for any failure, using the HTTP status codes in the table. -5. Honor `atomic: true` on batch requests when not rejected. +5. Honor `atomic: true` on batch requests. 6. Accept the registered parameter types in section 5 (`blob`, `bigint`). 7. Emit the `X-Http-Sql-Version` response header. From ad8883dc094e9e2a871e9e0834c60fd97f0e50de Mon Sep 17 00:00:00 2001 From: Sean Silvius Date: Sun, 2 Aug 2026 22:26:43 -0700 Subject: [PATCH 2/2] chore: retrigger CI (spec-sanity landed after this branch)