feat(verify): reusable checkReadCoercion driver conformance helper + cross-driver test#2671
Merged
Merged
Conversation
A stored value must read back as its declared type on every driver: a boolean as a JS boolean (not the integer 0/1 SQLite stores), a json field as an object/array (not serialized text), an integer as a number. When drivers disagree, code green on one silently breaks on another. This is the invariant behind the 2026-07-06 case_escalation incident (a boolean guard `field != true` read the field back as integer `1` on Turso, so `1 != true` was always true and the flow self-triggered forever, while the memory/better-sqlite3 repro was green). The storage-specific fixes live in each driver; this suite pins the shared contract so no framework driver — present or future — can reintroduce the gap. Runs against driver-sql (better-sqlite3) and driver-memory. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015EsQntpH9mUZqG7LAWzPAK
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Contributor
📓 Docs Drift CheckThis PR changes 2 package(s): 2 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:
|
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015EsQntpH9mUZqG7LAWzPAK
Promote the read-coercion contract from a service-datasource-local test into a reusable, driver-agnostic export in @objectstack/verify (mirrors checkLedger: returns a problems list, empty = conformant, no test-runner dependency). Any driver — including out-of-tree ones like cloud's driver-turso in remote mode — can now run the identical contract against itself. - verify: new checkReadCoercion(driver) + CoercibleDriver/ReadCoercionOptions. - service-datasource: the cross-driver conformance test now consumes the shared helper (driver-sql better-sqlite3 + driver-memory), asserting `toEqual([])`. - changeset: minor for @objectstack/verify (new public API). Verified: service-datasource conformance 2 passed; helper flags a raw non-coercing driver with 3 problems (boolean 1 / json text / numeric string); verify build incl. DTS clean. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015EsQntpH9mUZqG7LAWzPAK
os-zhuang
marked this pull request as ready for review
July 7, 2026 04:49
…nce in dogfood The prior commit added @objectstack/verify as a devDep of service-datasource, but verify already depends on service-datasource (via runtime) — turbo flagged the cycle and the build/typecheck/test jobs failed. - Move the cross-driver conformance test out of service-datasource into packages/dogfood (which already dev-tests through @objectstack/verify and runs as the Dogfood Regression Gate); add driver-sql + driver-memory as dogfood devDeps. No cycle: drivers don't depend on verify/dogfood. - Revert the service-datasource test + devDep. - checkReadCoercion now reads back its own row by id (robust when the probe object already holds rows); the memory-driver test uses `persistence: false` so the probe never leaks to a shared on-disk snapshot across suites. Verified: `turbo run build --filter=./packages/*` 60/60 (no cycle); full dogfood suite 191 passed / 39 files (incl. the new conformance test: both drivers → [], non-coercing stub → 3 problems); verify build incl. DTS clean; eslint clean. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015EsQntpH9mUZqG7LAWzPAK
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
A stored value must read back as its declared type on every driver: a
booleanas a JS boolean (not the integer0/1SQLite stores), ajsonfield as an object/array (not serialized text), anintegeras a number. When two drivers disagree, code green on one silently breaks on the other.This is the invariant behind the 2026-07-06
case_escalationincident: a boolean guardfield != trueread the field back as integer1on Turso, so1 != truewas always true and the flow self-triggered forever — while the local repro (memory / better-sqlite3, both of which coerce) was green in 6s. The storage-specific fixes live in each driver (driver-sql'sformatOutput; cloud'sdriver-tursoremote path — cloud PR #753, merged). This PR adds the shared, checked contract.What
@objectstack/verify: newcheckReadCoercion(driver)— a reusable, driver-agnostic conformance helper. Mirrors the existingcheckLedgeridiom: returns a list of problems (empty = conformant) with no test-runner dependency, and takes any driver structurally (CoercibleDriver), so out-of-tree drivers — e.g. cloud'sdriver-tursoin remote mode — can run the identical contract against themselves. Reads back its own row by id so it's robust when the probe object already holds rows.packages/dogfood: a cross-driver conformance test consumes the shared helper, running it againstdriver-sql(better-sqlite3:memory:) anddriver-memory(assertingtoEqual([])) plus a negative check that a raw non-coercing driver yields 3 problems. (dogfood already tests through@objectstack/verifyand runs as the Dogfood Regression Gate; drivers added as its devDeps.)@objectstack/verify(new public API).Verification (built from source, run locally + CI green)
[]; non-coercing stub → 3 problems).turbo run build --filter=./packages/*60/60 (no dependency cycle).@objectstack/verifybuild incl. DTS clean; ESLint clean.Follow-up (separate, needs a framework SHA bump in cloud)
Cloud's
driver-tursoremote-read test can switch to importingcheckReadCoercionfrom@objectstack/verifyto run the identical contract against itself in remote mode — lands whenever cloud next bumps.framework-sha(not worth a dedicated bump on its own).🤖 Generated with Claude Code
https://claude.ai/code/session_015EsQntpH9mUZqG7LAWzPAK