ADR-0118 D1 declares transaction on IObjectQLEngine and writes its caveats into the contract TSDoc as declared meaning rather than hidden behaviour. Declaring them is not fixing them. These are the three, recorded while scoping #4612.
All three are in ObjectQL.transaction(), packages/objectql/src/engine.ts:4934-4973.
1. Silent degrade when the driver has no beginTransaction (:4952-4954)
if (!drv?.beginTransaction) { return callback(baseContext); }
The callback runs with no transaction and no rollback, and the caller cannot tell. Every in-tree driver implements beginTransaction (it is required on IDataDriver), so this path exists for test doubles and foreign engines — but a caller asking for a transaction and silently not getting one is the failure mode that made batchData's atomic flag a lie for as long as it was (ADR-0118 D4). Proposal: warn-once, or an explicit opts.require: true that throws instead of degrading. ADR-0118 D4's batchData gate is the fail-closed pattern to generalize.
2. Default-driver-only (:4950)
const drv = this.drivers.get(this.defaultDriver) as any;
Objects mapped to another datasource via setDatasourceMapping are written outside the transaction with no diagnostic, so a multi-datasource "atomic" write partially commits. Refusing loudly when the operations inside a transaction span drivers would be a real improvement over today's silent partial commit; genuine cross-driver atomicity is a much larger design question (two-phase commit) and is explicitly not what this asks for.
3. No owned-vs-joined signal (:4946-4948)
Per ADR-0067 D2 a nested transaction() joins the ambient transaction and returns without owning commit/rollback. That is correct, but the caller cannot distinguish "I own this transaction" from "I joined someone else's". It matters for any caller whose response claims durability: batchData's rolled-back response (ADR-0118 D4) asserts prior ops were undone, which is only locally guaranteed when it owns the transaction. Today's callers are all top-level so the claim holds; nothing enforces that it keeps holding. Proposal: transaction(cb, base, opts?) surfacing an owned signal to the callback.
Refs: ADR-0118 D1, ADR-0034, ADR-0067 D2, #4612.
ADR-0118 D1 declares
transactiononIObjectQLEngineand writes its caveats into the contract TSDoc as declared meaning rather than hidden behaviour. Declaring them is not fixing them. These are the three, recorded while scoping #4612.All three are in
ObjectQL.transaction(),packages/objectql/src/engine.ts:4934-4973.1. Silent degrade when the driver has no
beginTransaction(:4952-4954)The callback runs with no transaction and no rollback, and the caller cannot tell. Every in-tree driver implements
beginTransaction(it is required onIDataDriver), so this path exists for test doubles and foreign engines — but a caller asking for a transaction and silently not getting one is the failure mode that madebatchData'satomicflag a lie for as long as it was (ADR-0118 D4). Proposal: warn-once, or an explicitopts.require: truethat throws instead of degrading. ADR-0118 D4'sbatchDatagate is the fail-closed pattern to generalize.2. Default-driver-only (
:4950)Objects mapped to another datasource via
setDatasourceMappingare written outside the transaction with no diagnostic, so a multi-datasource "atomic" write partially commits. Refusing loudly when the operations inside a transaction span drivers would be a real improvement over today's silent partial commit; genuine cross-driver atomicity is a much larger design question (two-phase commit) and is explicitly not what this asks for.3. No owned-vs-joined signal (
:4946-4948)Per ADR-0067 D2 a nested
transaction()joins the ambient transaction and returns without owning commit/rollback. That is correct, but the caller cannot distinguish "I own this transaction" from "I joined someone else's". It matters for any caller whose response claims durability:batchData's rolled-back response (ADR-0118 D4) asserts prior ops were undone, which is only locally guaranteed when it owns the transaction. Today's callers are all top-level so the claim holds; nothing enforces that it keeps holding. Proposal:transaction(cb, base, opts?)surfacing anownedsignal to the callback.Refs: ADR-0118 D1, ADR-0034, ADR-0067 D2, #4612.