Skip to content

test(driver-turso): pin the unbacked-conflict-target refusal across both faces (#8568) - #8579

Merged
os-zhuang merged 1 commit into
mainfrom
claude/issue-8568-cross-face-refusal-parity-pin
Aug 13, 2026
Merged

test(driver-turso): pin the unbacked-conflict-target refusal across both faces (#8568)#8579
os-zhuang merged 1 commit into
mainfrom
claude/issue-8568-cross-face-refusal-parity-pin

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

Fixes#8568

Test-only. Adds the cross-face parity pin for the unbacked-conflict-target refusal to packages/drivers/driver-turso/src/turso-local-remote-unique-parity.test.ts, beside the existing remote-only Pin 3.

What was missing

One condition — a conflictKeys upsert whose target no unique index backs — is refused on both TursoDriver faces, in one wording by #5240. Both existing pins are single-face and each pins its own wording as a literal:

So a reword of one package, with its own literal updated in the same commit, drifts the pair while every suite stays green. TursoDriver picks its face from url, so that drift makes the answer to one condition a property of the connection string.

The assertion

Two RUNTIME errors, raised from one condition on both faces, compared to each other — never each against its own literal, which is the form that stays green forever while the faces diverge:

expect(localErr!.message).toBe(remoteErr!.message);expect(localErr!.code).toBe(remoteErr!.code);expect(localErr!.status).toBe(remoteErr!.status);

Two guards around it, both load-bearing:

Plus a two-face positive control, mirroring Pin 3's: a pair of faces refusing every conflictKeys upsert would agree perfectly, so both must still MERGE on a backed target.

Reverse verification — direction predicted per leg, both legs run

Two-way redness is the whole property; a pin red on one leg only is the one-way pin this card replaces.

legrewordedparity pinrest of this file
1LOCAL only (driver-sql)RED, 1 failed / 9 passed9 green
2REMOTE only (driver-turso)RED, 1 failed / 9 passed9 green

Leg 2 is the one worth reading: under it every pre-existing pin stayed green, Pin 3 included — its assertions are token regexes (/crm_contact_plain/, /email/, /unique/i) that a reword preserving those words walks straight past. That is precisely how the drift could have landed unnoticed. In leg 1, #8445's own literal pin also went red, which is the literal a drifting author updates in the same commit.

One measured trap recorded in the file header: the local face arrives through the BUILT @objectstack/driver-sql (this package resolves the workspace dependency to its dist, no vitest alias to src), so leg 1 ran GREEN against a stale dist until that package was rebuilt — which reads exactly like a pin that does not work.

Both reworded faces were restored from the commit; git diff origin/main --stat is the one test file, 117 insertions.

Scope and changeset

No production code — sql-driver.ts and remote-transport.ts are untouched in the diff. Nothing user-visible ships, so this takes the skip-changeset label rather than a changeset file; check-empty-changeset bans a stub, and a declaring changeset would announce a release note for a change no consumer can observe.

Related: #8445, #8413, #5240 (one condition, one wording), #6203 / #5769 (the two-answers-per-connection-string defect class).


Generated by Claude Code

…oth faces (#8568)
The refusal is pinned on the remote face here and on the local face in
driver-sql's own suite, each against its OWN literal — so a reword of one
package that updates its own literal drifts the pair with every suite green.
TursoDriver picks its face from url, so that drift makes the answer to one
condition a property of the connection string (#5240).
Adds a local-face case beside Pin 3 that raises the same condition on both
faces and compares the two RUNTIME errors to each other (message, code,
status), plus a two-face positive control so the agreement cannot be bought
by refusing every conflictKeys upsert.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VoxQqG5FiUHZKCST7KDoZC
@vercel

vercelBot commented Aug 13, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
ProjectDeploymentActionsUpdated (UTC)
objectstackIgnoredIgnoredAug 13, 2026 11:19pm

Request Review

@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

No hand-written docs reference the 0 changed package(s). ✅

@os-zhuangos-zhuang added skip-changeset PR has no user-facing published change; bypasses the changeset gate and removed tests labels Aug 13, 2026 — with Claude
@os-zhuangClaude

Copy link
Copy Markdown
ContributorAuthor

ACCEPT — reviewed against the tree at 20115877, not against the report.

The one thing this card could have gotten wrong is the thing it exists to prevent, so I checked that first and directly:

expect(localErr!.message).toBe(remoteErr!.message);expect(localErr!.code).toBe(remoteErr!.code);expect(localErr!.status).toBe(remoteErr!.status);

Two runtime values, compared to each other. Not each against its own literal — which is the form that stays green forever while the faces drift, i.e. the defect re-created inside its own fix. Confirmed present in the diff, not merely described.

Verified independently of the description:

  • The refusal guard is real, not decorative.captureError returns null on success (:129-136), so without the { local: true, remote: true } assertion a face that stopped refusing would reach the comparison holding null and report a TypeError instead of the divergence. The guard converts that into the right failure.
  • The anchor is a value assertion, not a second wording literal.VALIDATION_ERROR / 400 plus the cause regex. This is load-bearing for a reason the card didn't have to state: agreement alone is bought by both faces regressing together — two raw SqliteErrors agree on SQLITE_ERROR/undefined perfectly. Anchoring on the envelope closes that, while still letting an identical reword of both faces stay green, which is what { field: {} }(零个操作符的字段约束)在同仓有三个答案:driver-sql 组合子内 TRUE、顶层抛 INVALID_FILTER、formula/driver-memory FALSE #5240 actually asks for.
  • The positive control is doubled and necessary. Two faces refusing every conflictKeys upsert would satisfy the parity assertion completely; both must still MERGE on a backed target.
  • The bypassTenantAudit: true asymmetry between the two calls is this file's existing convention, not something introduced here — Pin 3 at :215-218 calls the pair the same way. I checked this because an ad-hoc asymmetry between the two faces would have meant the pin was comparing two different code paths.
  • Imports and fixtures all pre-exist (StandardErrorCode from @objectstack/spec/api, CONTACT_NO_UNIQUE at :115) — the diff adds none, so a missing one would have been a typecheck failure rather than a review finding.

Reverse verification, both legs, is the part that makes this a pin rather than a decoration. Leg 2 is the one that matters: rewording only the remote face turns it red while all nine pre-existing cases stay green — Pin 3 included, because its assertions are token regexes (/crm_contact_plain/, /email/, /unique/i) that a reword preserving those words walks straight past. That is a measurement of the blind spot, not an argument about it.

The stale-dist trap recorded in the file header is worth more than the pin in the long run: the local face arrives through the built@objectstack/driver-sql, so leg 1 ran green against a stale dist before a rebuild — reading exactly like a pin that does not work. Anyone re-running this verification would have hit it and drawn the opposite conclusion.

Scope and disposition: git diff origin/main --stat is the one test file, +117/−1; sql-driver.ts and remote-transport.ts are untouched, so both reworded faces were restored cleanly. Path surface is packages/drivers/** only — no docs/adr/**, no .claude/skills/** — so this is the seat's to queue. skip-changeset is the right call: nothing user-visible ships, and check-empty-changeset bans the stub that would otherwise announce a release note for a change no consumer can observe.

Holding ready + merge queue until all 24 check runs report green — several are still in_progress, and the aggregate status field is not evidence here (it covers only the Vercel commit status and reads success while jobs are still running).


Generated by Claude Code

@os-zhuang
os-zhuang marked this pull request as ready for review August 13, 2026 23:43
@os-zhuang
os-zhuang added this pull request to the merge queueAug 13, 2026
Merged via the queue into main with commit a3b1d26Aug 13, 2026
33 checks passed
@os-zhuang
os-zhuang deleted the claude/issue-8568-cross-face-refusal-parity-pin branch August 13, 2026 23:55
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/mskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

drivers(turso): the unbacked-conflict-target refusal has no cross-face parity pin — the two wordings can drift without a test noticing

2 participants

@os-zhuang@claude