Repository navigation
fix(driver-turso,driver-sql): refusals and log lines state each decision in words instead of a tracker number (stage 4) - #20877
Conversation
…ided without a tracker number The three aggregate refusals stage 1 held (undeclared function, count_distinct without a field, per-aggregation filter) drop their citation on both faces in one commit, so the byte-parity tests between driver-sql and the Turso remote transport keep comparing one sentence. The remote transport's declared-but-uncompiled and date-bucket refusals drop theirs too, which makes them equal to driver-sql's copies again. Each sentence already stated the decision, so only the citation goes. The prose-id ledger is recomputed with --census-ledger: the driver-sql row leaves, and remote-transport.ts goes from 40 to 35 occurrences. Claude-Session: https://claude.ai/code/session_01DEvba2nBuD4tWzfq8r8NFY Co-authored-by: Claude <noreply@anthropic.com>
… say what was decided without a tracker number The remote transport's filter refusals (the withheld wire sentences and the full diagnostics behind them) drop their citations. Most of those numbers were bare ids from the repository this file used to live in, so here they resolved to unrelated cards. Where the sentence already stated the decision, only the citation goes. Two gain words: the non-boolean $null diagnostic now says every driver refuses it, so one filter no longer gets a different answer per backend, and the remote auto_number refusal says it refuses rather than resolves because resolving would write NULL into the slot. Two pins move onto the sentence: the $null test asserts the ruling in words instead of three ids, and the unbindable-comparand test asserts 'indistinguishable from "no rows matched".' instead of two ids. The prose-id ledger is recomputed: the remote-transport.ts row leaves, and turso-driver.ts keeps one occurrence (the log line). Claude-Session: https://claude.ai/code/session_01DEvba2nBuD4tWzfq8r8NFY Co-authored-by: Claude <noreply@anthropic.com>
… tracker number The unnumbered-upsert warning drops its citation; it already said what an operator should do. The remote canonical backfill's info line now says what a conversion buys (the converted rows hold the one canonical text form, and the column drops the unindexable read-side repair only once a pass finds nothing left to convert). The unresolvable-remainder warning replaces its cross-repo citation with the rule: a value that cannot be read as an instant is counted and reported, never guessed at. The prose-id ledger is recomputed: the last two driver-turso rows leave, so the package holds no ledgered id. Claude-Session: https://claude.ai/code/session_01DEvba2nBuD4tWzfq8r8NFY Co-authored-by: Claude <noreply@anthropic.com>
…he decision Claude-Session: https://claude.ai/code/session_01DEvba2nBuD4tWzfq8r8NFY Co-authored-by: Claude <noreply@anthropic.com>
📓 Docs Drift Check19 anchor(s) derived from 2 changed package(s); no hand-written page names any of them, so this run has nothing to list — not a clean bill of health. This check sees only pages that NAME a derived anchor: one that documents this change in prose, or enumerates it in an authoring dialect, names none and stays invisible to it on every run. What this run could not see
Coarse fallback — 14 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): Which tree this was computed onThis run read A worktree cut from an older # while this PR is open — GitHub drops the merge commit once it closes
git fetch origin d79a374a1b3dd100f13f77a912c06fcf4082b410 && git checkout d79a374a1b3dd100f13f77a912c06fcf4082b410
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 6c96b37be84c496bf3e0dd4b89cd17999a0f4f62 252a378f9908e75d931168a222b3c868e74ea2e4 && git checkout -B drift-repro 6c96b37be84c496bf3e0dd4b89cd17999a0f4f62 && git merge --no-ff 252a378f9908e75d931168a222b3c868e74ea2e4
node scripts/docs-audit/affected-docs.mjs --json 6c96b37be84c496bf3e0dd4b89cd17999a0f4f62 |
Contract reviewServed-tier: Read-only, at tier, adversarial to the dispatch. Inputs: card #20513 (body and all 25 comments — the census 5900801368, the ruling 5902360492 「20513 A」 A / A, the stage-4 claim 5912562820, the stage-4 Check-runs on ① Derived judgmentsScope against the ruling and the claim — right. The ruling orders stages per package until the ledger is empty, all three categories, form D, Text only — right, checked line by line. Every removed and added line in the four source files carries a string-literal delimiter; a filter of the diff for changed lines without one returns nothing. No Accept-set and public surface — nothing moves — right. No schema, filter grammar, DDL, route, wire Ledger diff — right, exact, recounted. Parsing the baseline at The three held pairs — right, both faces in one commit, and they read identically. At the head the function bodies of Form D, string by string — right. All 15 cited objectstack issues read
Where only the citation goes (28 literals): each sentence already carried the decision and is otherwise unchanged, and each readable card's title matches its sentence — the undeclared-function (5907), declared-but-uncompiled (5907), field-less Pins — right, 2 tests in 2 files. Review faces — right, with one wording note. The changeset (below) reads as a CHANGELOG entry: every family it names is in the diff, and each sentence it summarises matches the string. The PR body's table, counts, commit order and ledger numbers match the diff and the recount above; it carries ② Semver level
Clause-②: no — right. Nothing an author can write is widened or narrowed; the PR body carries ③ Boundary flagsDev flags (report 5913433803), each answered:
Implemented-by: VERDICT: PASS Generated by Claude Code |
Part of #20513
Clause-②: no
Stage 4 of 5 of this lane (
driver-turso), under the maintainer's A / A ruling on the card, plus the threedriver-sqlaggregate refusals stage 1 held for their Turso twins. The card stays open for stage 5, so this PR carries no closing keyword. Text only: no errorcode, field name, HTTP status, export or control flow moves. Every changed source line sits inside a string literal: a TypeScript-scanner skeleton of each of the four source files (every literal replaced by one placeholder, pure-literal+joins collapsed, comments dropped) is identical at the merge base and at the head, and the same check reports DIFF on a file with a real code change (control).What this does
The Turso driver's refusals and log lines sent the reader to a tracker number for the reason behind them. Most of the remote transport's numbers were bare ids from the repository that file used to live in (
remote-transport.tswas moved here from the cloud repository), so in this repository they resolve to unrelated cards: a Vercel deploy fix, a CLI command, a version-packages PR. Each rewritten string now says the reason in words (form D, as the migration-entry rewrite and stages 1 to 3 applied it). Where the sentence already stated what was decided, only the citation goes. Where it did not, the decision is added in words:remote-transport.tsnon-boolean$nulldiagnosticturso-driver.tsremoteauto_numberrefusal (thrown, 501)remote-canonical-backfill.tsinfo lineremote-canonical-backfill.tsunresolvable-remainder warning$between, undeclared and non-list combinator, non-node operand, non-objectwhere, empty operator map, undefined comparand, unbindable comparand and non-boolean$existsrefusals, and the unnumbered-upsert warningEach new sentence was checked against today's code, not only against the cited card: a non-boolean
$nullis refused by all five drivers (driver-sql'snonBooleanNullComparandError, inherited bydriver-sqlite-wasmand Turso local;driver-memory'sfilter-refusal.tsdoor and query path;driver-mongodb'smongodb-filter.ts; this transport);refuseUngeneratableRemoteAutonumberruns oncreate,bulkCreateand a match-key-lessupsert, andRemoteTransport.createbuilds its own INSERT withoutfillAutoNumberFields; the backfill marks a column canonical only when its post-pass probe finds nothing left to change, and leaves out-of-band digit rows alone, counted intounresolvedEpochTextRows.The three held pairs, moved together
Stage 1 held three
driver-sqlaggregate refusals (undeclared function,count_distinctwithoutfield, per-aggregationfilter) becausedriver-tursocompares them byte for byte with the remote transport's copies. Both faces drop the citation in one commit (fe71ac88e), and the pins stay byte-exact:remote-transport-aggregate-function-refusal.test.ts(the undeclaredmedian/array_agg/string_aggand miscased cases, the field-lesscount_distinctcase, the per-aggregation filter case) andremote-transport-undeclared-aggregate-keys.test.ts(thefunc:spelling) compare the two runtime messages. The same commit drops the remote declared-but-uncompiled and date-bucket citations, whosedriver-sqlcopies stage 1 already cleared, so those pairs read identically again.One-off ablation on the committed head, run under a shell trap: the three old citations planted back on the
driver-sqlface only (scripts/ablation-replace.mjs, each anchor hit once, disk-verified),driver-sqlrebuilt, each marker confirmed indist/(scripts/ablation-dist-preflight.mjs). The twodriver-tursofiles then gave 10 failed, 23 passed: every pair has a live pin. After the restore (blob equal to HEAD,git diff HEADempty), the rebuild, and all three markers confirmed absent fromdist/, they gave 33/33.git status --porcelainwas empty afterwards.remote-transport-compile-refusal-seam.test.tsderives the remote$betweenarity sentence fromdriver-sql's by stripping a parenthesised id. Neither side carries one any more, so that strip is now an identity; no sentence in this stage is derived that way.Order inside the stage
32 literals (47 occurrences) fit one PR, under the stop line, so the stage lands whole in four ordered commits. Each of the first three recomputes the ledger, so every commit is green on
check:doc-authoring:fe71ac88eauthor-visible: the aggregate refusal family, 8 literals on both faces;ab16ca922author-visible: the remote filter refusals and theauto_numberrefusal, 21 literals (36 occurrences), plus the two re-pinned tests;8c7541655log lines: 3 literals;252a378f9the changeset.driver-tursohas no ledgeredsrc/-shipped test string (its two testkits carry no id).Pins re-pinned: 2 tests in 2 test files (4 id assertions become 3 sentence assertions)
remote-transport-null-comparand-refusal.test.ts: "cites the ruling and the framework landing so both repos are findable" asserted three ids. It now states the ruling in words and asserts "It is refused rather than coerced" and "Every driver now refuses it, so one filter no longer gets a different answer per backend."remote-transport-comparand-refusal.test.ts234 matched two ids. It now assertsindistinguishable from "no rows matched".A one-off mutation proves each moved pin can fail, run on the committed head with
scripts/ablation-replace.mjsin wrap mode under a shell trap. The tests import the transport fromsrc, so no build leg applies. "Every driver now" to "Every backend now": 1 failed / 54 passed. Appending "here" after "no rows matched": 1 failed / 26 passed. After each leg the blob equals HEAD andgit diff HEADis empty; both files then gave 82/82, andgit status --porcelainhad 0 lines.No test outside
driver-tursopins a changed string. Every fragment of every changed sentence was searched in all test files of the repository: the hits are unrelated uses of common phrases, andrest'srest-4xx-message-truncation.test.ts, whose own copy of a$nullsentence is never compared with a driver's (see Acceptance notes).Ledger burn-down
scripts/doc-authoring-prose-id.baseline.jsonwas regenerated withnode scripts/check-doc-authoring.mjs --census-ledgerinto a scratch file, so the growth refusal ran against the checked-in baseline, and then copied into place. Only these four rows move, and every one leaves:driver-turso/src/remote-transport.tsdriver-turso/src/turso-driver.tsdriver-turso/src/remote-canonical-backfill.tsdriver-sql/src/sql-driver.ts(the three held)The ledger's file count goes from 204 to 200; the gate's printed pinned sites (id-bearing literals) go from 647 to 615. A census of every other package's (file, id) occurrences before and after is identical (722 = 722).
The census count, reconciled. The census counted 24 messages for
driver-turso; the ledger holds 44 occurrences. The gate counts 29 string literals. The census folds a+chain into one message, and five two-literal chains (the$existsdiagnostic, the undeclared-combinator tail, the$and/$orrequirement, and the cross-field and unbindable wire sentences) make 29 literals into 24 messages. Those 29 literals carry 44 occurrences, the census's own "id occurrences 44". Withdriver-sql's 3 held literals, this stage moves 32 literals and 47 occurrences.Verification (head
252a378f99)turbo run buildover./packages/*and./packages/*/*, 71/71, under the verify lock.driver-sqlwas rebuilt directly by the ablation's restore leg, anddriver-tursodirectly after the pin mutations (their restore rewroteremote-transport.ts). The new sentences are indist/index.jsof both packages; the only citations left in eitherdist/are docblocks.@objectstack/driver-tursotests (vitest run --maxWorkers=2, reading the rebuiltdriver-sqldist/): 80 files passed; 2,195 tests passed, 33 skipped.@objectstack/driver-sqltests: 201 files passed and 11 skipped (the live PG / MySQL cells; no server here); 3,254 tests passed, 188 skipped.@objectstack/driver-sqlite-wasm(extendsSqlDriver): 36 files, 675 tests passed.@objectstack/driver-tursoand@objectstack/driver-sqltypecheckexit 0;tsc --listFilesfordriver-tursoreads 80 test files, both re-pinned ones among them.node scripts/pm/dispatch-gates.mjs --commands(no paths; 8 paths against merge base72f8c3820) names 71 commands, and all 71 exit 0.check:type-check-debtfirst answered exit 3 (PREREQUISITE NOT MET:driver-turso's type entry older than its sources, after the mutation restore); after the directdriver-tursorebuild it exits 0, andcheck:dts-closure,check:dual-build-cjs-loadsandcheck:lean-entry-closurewere re-run there too.--ranwith exit codes recorded: "71 derived, 71 run, 0 NOT-MEASURED, 0 UNRUN".check:doc-authoring: "sibling-package prose ids hold the baseline — 615 pinned site(s) across 200 file(s) ... no growth, no burn-down unrecorded".eslint --no-inline-config --format jsonover the 6 touched.tsfiles reports 6 files, 0 errors, 0 warnings. The resolvedparserOptionsareecmaVersion: latestandsourceType: moduleonly, with noprojectorprojectService, so no type-aware rule can move an untouched file. Repo-widepnpm lintis CI's.driver-sqlsuite (the requiredTemporal Conformance (live PG + MySQL)job runs them), the Test Core shards, Dogfood, and the workspace type-check lanes.origin/mainmoved 4 commits after the branch point; none touches these files or the ledger, and CI tests the merge ref.Acceptance notes
domain:enginepackages (645 sites, 160 numbers, 104 files): the ruling C+D stage for this lane (from #20556) #20595).remote-transport.ts's comments and docblocks still cite those bare cloud ids, which in this repository resolve to unrelated cards. Comments are outside this ruling and belong to dead tracker citations in thedomain:enginepackages (645 sites, 160 numbers, 104 files): the ruling C+D stage for this lane (from #20556) #20595.driver-memory's non-boolean$nullrefusal (filter-refusal.ts) still ends with its citation;driver-memoryis in stage 5.rest'srest-4xx-message-truncation.test.tsbuilds its own copy ofdriver-sql's$nullsentence, citation included, as a truncation fixture. It is a test file outside the ledger, and nothing compares it with the driver's text.driver-turso's*.test.tsfiles still carry cloud ids (for example the refusal-envelope table inremote-transport-null-comparand-refusal.test.ts). They are test files, outside the ledger and outside the ruling's shipped-src/scope.$nullsentence says "every driver", not "every evaluator":@objectstack/formula'smatchesFilterreads a non-true$nullas IS NOT NULL. Nothing here measured a public door that hands it a non-boolean, so this is a reading only.Generated by Claude Code