Repository navigation
fix(runtime): the SQLite file-path refusal names what the operator can change - #24039
Conversation
…n change The remedy after "does not look like a file path" told an operator who had set OS_DATABASE_DRIVER to "set OS_DATABASE_DRIVER explicitly". Over a scheme it now names a file: path for the selected kind, or a driver that matches the URL (unset the selection so the URL selects it, or set it to the URL's driver), naming every door a selection comes through. Over a file: that names no file it names the file only: that arm is also reached with no selection at all, and a driver change never gets past it. Claude-Session: https://claude.ai/code/session_018t6a5rvqPRvEDMCVVW9kYT Co-authored-by: Claude <noreply@anthropic.com>
…lite-refusal-remedy
…medy once Claude-Session: https://claude.ai/code/session_018t6a5rvqPRvEDMCVVW9kYT Co-authored-by: Claude <noreply@anthropic.com>
📓 Docs Drift Check1 anchor(s) derived from 1 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 — 26 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 42cbe84538688b049270067d329893b8131e36f4 && git checkout 42cbe84538688b049270067d329893b8131e36f4
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 2b274600b1361b6a39b078e965443ddb3ddace79 012b450951aed6e81e1011d70ca7a29fe722dd0f && git checkout -B drift-repro 2b274600b1361b6a39b078e965443ddb3ddace79 && git merge --no-ff 012b450951aed6e81e1011d70ca7a29fe722dd0f
node scripts/docs-audit/affected-docs.mjs --json 2b274600b1361b6a39b078e965443ddb3ddace79 |
席位核对ACCEPT · #23898 ·
Noted, not filed (the dev's, as Landing: Generated by Claude Code |
Fixes #23898
Clause-②: no
What changes
sqliteFilenameFromUrlinpackages/runtime/src/standalone-stack.tsraises the refusal "KIND driver was selected but the URL does not look like a file path (WHY)." Both hosts print it: the standalone host tags it[StandaloneStack], and the CLI's legacyos servepath prints it untagged as the fatalUnsupportedDriverError. The first clause is unchanged, and so are the rule, the set of refused inputs, the error class, the exit and the scheme-only naming. Only the advice after the first clause changes.its scheme is "SCHEME"Use file:/path/to/db.sqlite, or set OS_DATABASE_DRIVER explicitly.Use file:/path/to/db.sqlite to keep the KIND driver, or use a driver that matches the URL: unset the driver selection (OS_DATABASE_DRIVER, --database-driver or the databaseDriver option) so the URL selects it, or set the selection to the URL's driver.it names no file after "file:"Use file:/path/to/db.sqlite, or set OS_DATABASE_DRIVER explicitly.Name the file after "file:", as in file:/path/to/db.sqlite.Why each arm gets its own remedy. The card says this refusal reaches an operator "only under an explicit
sqlite/sqlite-wasmselection". I measured that on the public door, and it holds for the scheme arm but not for the empty-file:arm.OS_DATABASE_URL=file: os serve --dev, with no driver selected, gets the empty-file:refusal on both hosts (table below). Afile:URL selects thesqlitekind on its own, so any driver advice on that arm would send the operator around a loop: unsetting the selection hands the URL straight back tosqlite. On that arm the remedy names the file and nothing else. On the scheme arm it carries both options the card's Done-looks-like names. The selection doors are listed and none is assumed, because the kind may have come fromOS_DATABASE_DRIVER(which--database-driversets), from thedatabaseDriveroption, or from the URL.CLI host. It holds no copy of the sentence.
sqliteFileForinpackages/cli/src/utils/storage-driver.tsre-raises the runtime's message with the tag stripped, so the CLI is not edited.driver-vocabulary-parity.test.tsstill holds the two hosts equal (green, below). Its rows carry the WHY fragment, and the whole sentence is held by derivation (toBe(sentence.replace(...))) rather than by a literal sentence row, so no remedy row was added there.Public door, base
fd0e72abcvs head012b45095Each case ran from a fresh directory outside the repo with
node packages/cli/bin/run.js serve --dev. The standalone host cases used a minimalobjectstack.config.ts. The CLI host cases setOS_MODE=offand used a config that declares one object, because the legacy path resolves storage only for a stack that declares objects. Every case exited 1.PLACEHOLDERappeared 0 times in every output, and no directory was created in the case directory on either tree.OS_DATABASE_DRIVER=sqlite,jdbc:postgresql://127.0.0.1:5999/db(its scheme is "jdbc:"). Use file:/path/to/db.sqlite, or set OS_DATABASE_DRIVER explicitly.(its scheme is "jdbc:"). Use file:/path/to/db.sqlite to keep the sqlite driver, or use a driver that matches the URL: unset ... or set the selection to the URL's driver.OS_DATABASE_DRIVER=sqlite-wasm,postgres://PLACEHOLDER-USER:PLACEHOLDER-SECRET@127.0.0.1:5999/db(its scheme is "postgres://"). Use file:/path/to/db.sqlite, or set OS_DATABASE_DRIVER explicitly.(its scheme is "postgres://"). Use file:/path/to/db.sqlite to keep the sqlite-wasm driver, or use a driver that matches the URL: ...OS_MODE=off), the same twoOS_DATABASE_URL=file:(it names no file after "file:"). Use file:/path/to/db.sqlite, or set OS_DATABASE_DRIVER explicitly.(it names no file after "file:"). Name the file after "file:", as in file:/path/to/db.sqlite.Following the new remedy's unset leg for the card's own URL (
OS_DATABASE_URL=jdbc:postgresql://127.0.0.1:5999/db, no driver) on head exits 1 with[StandaloneStack] Unsupported database URL scheme "jdbc:". Supported schemes: postgres://, pg://, .... So the next refusal names the drivers that exist.Tests (head
012b45095)pnpm --filter @objectstack/runtime exec vitest run --project local --maxWorkers=2: exit 0,Test Files 404 passed (404),Tests 6157 passed | 19 skipped (6176).pnpm --filter @objectstack/cli exec vitest run --project unit --maxWorkers=2 src/utils/driver-vocabulary-parity.test.ts src/utils/storage-driver.test.ts: exit 0,Test Files 2 passed (2),Tests 204 passed (204).@objectstack/runtimeresolves to itsdist/there, which was rebuilt at head first (grep -c 'unset the driver selection'gives 1 in bothdist/index.jsanddist/index.cjs).pnpm --filter @objectstack/runtime typecheck: exit 0.pnpm --filter @objectstack/cli typecheck: exit 0. The runtime'stsconfig.jsonexcludes tests. The changed test compiles in the test layer (check:test-typecheckOK), and it is not intest-typecheck-debt.json.standalone-stack-explicit-sqlite-non-file-refusal.test.ts(98 tests in the file, 18 of them new):file:arm viafile:andFILE:, with no selection (thedatabaseUrloption andOS_DATABASE_URL) and with an explicitsqliteselection (both doors).Ablation (one-off, no permanent file)
The fix was committed first.
node scripts/ablation-replace.mjswrote the old remedy back intostandalone-stack.ts:6ddd65e0af79to9d5038cced7e;The suite imports
./standalone-stack.jsrelatively, so it readssrc/and no rebuild leg was needed. Result:Tests 18 failed | 80 passed (98). The 18 red rows are exactly the new remedy rows, and the 80 first-clause, credential and control rows stayed green. Restore: blob after restore equals HEAD (6ddd65e0af79), andgit diff HEADis empty.Gates (head
012b45095)node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstackderived 62 commands from merge base9e797a897. All 62 ran locally, each exit recorded before any pipe.--ranreconciliation: exit 0,62 derived famil(ies) accounted for — 60 run, 2 NOT-MEASURED.pnpm check:dual-build-cjs-loads(exit 3, PREREQUISITE NOT MET): it reads built output from packages outside this diff's closure that this checkout has not built. CI runs it on a full build.pnpm check:type-check-debt(exit 3): its own build leg timed out waiting for the shared verify lock. CI runs it.pnpm exec eslint --no-inline-config packages/runtime/src/standalone-stack.ts packages/runtime/src/standalone-stack-explicit-sqlite-non-file-refusal.test.ts: exit 0, 0 errors and 0 warnings on each file, and neither was ignored. The repo-wide lint run is the PR'sLint & Repo Gatescheck-run.Acceptance notes
file:(orsqlite:, orwasm-sqlite://) prefix that wraps aSCHEME://value reaches it. Measured on both trees:OS_DATABASE_URL=file:postgres://PLACEHOLDER-USER:PLACEHOLDER-SECRET@127.0.0.1:5999/dbgets(its scheme is "postgres://"), with the credentials absent. There the new remedy's first option (afile:path) is the fix, and its "unset the driver selection" leg does nothing because nothing was selected. No sentence is false, so this is an observation, not a defect. Carrier: none..changeset/23863-explicit-sqlite-non-file-refusal.mdquotes the old remedy in its "After" sentence. That changeset and this one are both pending, so they ship in the same release, and this changeset's FROM/TO supersedes the quote. It is outside this card's file surface and was not edited.content/,skills/anddocs/quote neither the first clause nor the remedy (git grepcount 0 at head). The positive control is the same grep overpackages/, which hits.Generated by Claude Code