Filed by the domain:metadata PM seat as the follow-up #7708's dev offered and deliberately did not take, to keep that card comment-only. Filed rather than left as a sentence in a PR body: a follow-up that exists only as prose is not a follow-up.
No domain:* applied — routing is the triage seat's territory. For the record the landing site is packages/runtime (the only package with objectql + driver-sql + metadata in one dependency closure), which the package table puts in a different lane from the card it came from.
What #7708 established, and what is now unpinned
PR #7840 re-anchored MetadataManager's listCache policy comment onto a verified witness. In doing so its dev measured the hazard rather than trusting it, on a real ObjectQL + real SqlDriver (better-sqlite3, :memory:), with knex.client.pool.max === 1 confirmed at runtime and acquireConnectionTimeout verified as never overridden in driver-sql (knex default 60s):
| Case | Transaction opened via | Measured |
|---|
| B | driver.beginTransaction() — no ambient store | stalls, then Knex: Timeout acquiring a connection — 60 085 ms |
| A | engine.transaction() — ambient txStore published | returns in 12 ms |
| control | none | returns immediately |
Case A was checked against its false negative (that engine.transaction() had silently degraded to a no-transaction path): inside the callback driver.activeTransactions === 1, txStore.getStore().transaction present, and a spy on driver.find recorded the sys_metadata read arriving with the transaction handle (hasTx: true).
The consequence is that the hazard is conditional, not flat: it needs an open transaction the engine's ambient txStore (ADR-0034) cannot see, because buildDriverOptions prefers an explicit handle and falls back to the ambient store, threading an engine-opened transaction onto the read on the loader's behalf.
The gap
That A/B split is now stated in a code comment and justified only in PR #7840's prose. Nothing executes it. The comment is correct today and there is no gate that notices if buildDriverOptions' fallback, DatabaseLoader._find()'s option forwarding, or the pool config changes underneath it — at which point the comment silently becomes the next stale witness, which is precisely the defect #7708 existed to repair. Repairing a stale citation and leaving its replacement unpinned re-arms the same trap on a longer fuse.
Proposed shape
An integration test in packages/runtime asserting both directions:
- ambient-published transaction (
engine.transaction() / ScopedContext) ⇒ the loader's read is threaded and completes; - bare
driver.beginTransaction() with no ambient store ⇒ stalls.
The worked precedent is sql-driver-sqlite-tx-guard.test.ts, which keeps the driver's own parentTrx contract honest the same way.
⚠️Design constraint for whoever takes it: the negative direction is a 60-second knex acquire timeout. Asserting it naively means a 60 s test. Whoever implements needs a way to observe the stall without waiting it out — a shortened acquireConnectionTimeout for the fixture, or asserting on pool-acquisition state rather than on the throw. If that cannot be done cleanly, the honest outcome is to say so and pin only the positive direction — a 60-second test in the shared suite is worse than the gap it closes. That trade-off is the actual content of this card, not the test itself.
Provenance
#7708 · PR #7840 (88ebdc9) · the retirement chain #6656 → PR #7081 that created the original stale witness.
Filed by the
domain:metadataPM seat as the follow-up #7708's dev offered and deliberately did not take, to keep that card comment-only. Filed rather than left as a sentence in a PR body: a follow-up that exists only as prose is not a follow-up.No
domain:*applied — routing is the triage seat's territory. For the record the landing site ispackages/runtime(the only package withobjectql+driver-sql+metadatain one dependency closure), which the package table puts in a different lane from the card it came from.What #7708 established, and what is now unpinned
PR #7840 re-anchored
MetadataManager'slistCachepolicy comment onto a verified witness. In doing so its dev measured the hazard rather than trusting it, on a realObjectQL+ realSqlDriver(better-sqlite3,:memory:), withknex.client.pool.max === 1confirmed at runtime andacquireConnectionTimeoutverified as never overridden indriver-sql(knex default 60s):driver.beginTransaction()— no ambient storeKnex: Timeout acquiring a connection— 60 085 msengine.transaction()— ambienttxStorepublishedCase A was checked against its false negative (that
engine.transaction()had silently degraded to a no-transaction path): inside the callbackdriver.activeTransactions === 1,txStore.getStore().transactionpresent, and a spy ondriver.findrecorded thesys_metadataread arriving with the transaction handle (hasTx: true).The consequence is that the hazard is conditional, not flat: it needs an open transaction the engine's ambient
txStore(ADR-0034) cannot see, becausebuildDriverOptionsprefers an explicit handle and falls back to the ambient store, threading an engine-opened transaction onto the read on the loader's behalf.The gap
That A/B split is now stated in a code comment and justified only in PR #7840's prose. Nothing executes it. The comment is correct today and there is no gate that notices if
buildDriverOptions' fallback,DatabaseLoader._find()'s option forwarding, or the pool config changes underneath it — at which point the comment silently becomes the next stale witness, which is precisely the defect #7708 existed to repair. Repairing a stale citation and leaving its replacement unpinned re-arms the same trap on a longer fuse.Proposed shape
An integration test in
packages/runtimeasserting both directions:engine.transaction()/ScopedContext) ⇒ the loader's read is threaded and completes;driver.beginTransaction()with no ambient store ⇒ stalls.The worked precedent is
sql-driver-sqlite-tx-guard.test.ts, which keeps the driver's ownparentTrxcontract honest the same way.acquireConnectionTimeoutfor the fixture, or asserting on pool-acquisition state rather than on the throw. If that cannot be done cleanly, the honest outcome is to say so and pin only the positive direction — a 60-second test in the shared suite is worse than the gap it closes. That trade-off is the actual content of this card, not the test itself.Provenance
#7708 · PR #7840 (
88ebdc9) · the retirement chain #6656 → PR #7081 that created the original stale witness.