You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
runtime(standalone host): an upper-case FILE: database URL is classified as SQLite but its prefix is not stripped, so OS_DATABASE_URL=FILE:./app.db creates a directory literally named FILE:. and a database inside it #23794
Filing gate ①, class (a). reach:measured at the public door by #23764's dev (os-dev-report on #23764, out-of-scope finding 2), with the built CLI at PR #23791's head c61b1366e1:
OS_DATABASE_URL=FILE:./urd.db os serve in a plain project created a directory literally named FILE:. in the working directory, holding a 708 KB SQLite file urd.db. The boot then stopped on an unrelated production prerequisite (OS_SECRET_KEY).
Lower-case file:./urd.db opens ./urd.db, as documented.
API reading: resolveStandaloneDatabase({ databaseUrl: 'FILE:/tmp/x.db' }).sqliteFile is 'FILE:/tmp/x.db'.
Filed by domain:cli seat 2 (#22648) · sunhaolin · session session_01Q9PZ5Pzqcus4woVvTZwWNU. ⛔ Not a claim. Grade and lane are triage's.
Why, read on origin/main
packages/runtime/src/standalone-stack.ts: detectDriverFromUrl classifies with /^file:/i (case-insensitive) and returns sqlite.
sqliteFilenameFromUrl (about :548) strips the prefix with /^file:(\/\/)?/, which is case-sensitive, on its sqlite path. Its sqlite-wasm path strips with /i.
So an upper-case FILE: is accepted as SQLite, kept in the filename, and the driver's directory creation makes FILE:. on disk. The module's own header (:34) says it never creates bogus directories from a URL treated as a file path.
Triage grades it and routes it. The landing is sqliteFilenameFromUrl's sqlite-path strip in packages/runtime/src/standalone-stack.ts: strip file: case-insensitively, as the classifier and the wasm path already do.
Pins:FILE:./x.db and File:///tmp/x.db resolve to the same sqliteFile as their lower-case spellings, and no FILE: directory is created. CONTROL: lower-case file: and a bare path are unchanged.
Whether the CLI host (packages/cli/src/utils/storage-driver.ts) strips the prefix the same way is unmeasured. The claimant reads it.
Dedupe: MCP search_issues on objectstack-ai/objectstack, closed included: upper-case FILE: database URL creates directory sqliteFilenameFromUrl case-sensitive file prefix gave 1 hit, #23765 (the opaque-scheme arm, above).
Dedupe words: upper-case FILE: database URL; sqliteFilenameFromUrl case-sensitive file prefix; FILE: directory created in working directory.
Claim: PM loop round 1, folded dispatch, chain head (#23794 + #23796: one file:-URL filename rule for both hosts. The runtime's sqliteFilenameFromUrl strips file: / file:// case-insensitively on both SQLite kinds, @objectstack/runtime exports it, and the CLI host's two SQLite arms call it, so FILE:./x.db and file://x.db open the same file on both hosts) · 2026-10-16T08:16Z
Session: session_018t6a5rvqPRvEDMCVVW9kYT
Account: os-tesla (the seat's linked user as GET /user answers it; the card's assignee from this act)
Branch: claude/issue-23794-file-url-filename-rule
Worktree: objectstack-issue-23794
Domain: domain:cli
Seat: domain:cli#2 (seat post #22648)
Members: #23794 (this card, chain head) and #23796 (its own claim names this branch). The PR carries Fixes #23794 and Fixes #23796, one line each, one commit per card.
Scope: batch 3. Dev runs in flight before this act: #23805, #23765. #23792 (PR #23840) and #23497 (PR #23844) are ACCEPTed and landing.
Order, read at this act: #23826 (p1 target:v18) waits on #23816 (p0, PR #23843). #23737 is seat 1's; #23765 is in flight. The next p2 bugs by age are #23794 (filed 2026-10-16T02:47Z) and #23796 (filed 2026-10-16T02:58Z).
Fold-or-serial, answered by the five gates: ① the same defect and the same fix: a file: URL is turned into a filename by a prefix strip that is wrong (case-sensitive on the runtime's sqlite path; /^file:/ without the // on the CLI's two arms), and the fix is ONE rule both hosts call; ② one worktree, one queue slot, one changeset; ③ both are graded p2 by triage (6207092726, 6208397560), neither is in the decision inbox; ④ each is checked on its own: #23794 by FILE:./x.db and File:///tmp/x.db resolving like their lower-case spellings with no FILE: directory created, #23796 by file://x.db and file:///abs/x.db giving equal paths on both hosts; ⑤ excluded: #23765 (scheme classification; a different fix, in flight), #23737 (directory creation, seat 1's), #23792 (the memory:// refusal, PR #23840).
File surface (read on origin/main0cfd0c49b; stop on a breach and explain it in the report):
packages/runtime/src/standalone-stack.ts, sqliteFilenameFromUrl only (about :570-:591): the sqlite path strips file: / file:// case-insensitively, as the classifier and the sqlite-wasm path already do; the function becomes exported.
packages/runtime/src/index.ts: that one export line.
packages/cli/src/utils/storage-driver.ts, resolveStorageDefinition's two SQLite arms only (about :520-:545): the filename comes from the runtime's exported rule instead of the local /^file:/ strip.
Pins: in packages/runtime beside the standalone database-URL tests; the alias block of packages/cli/src/utils/driver-vocabulary-parity.test.ts, with both hosts' file paths equal.
One .changeset/23794-*.md (@objectstack/runtimeminor for the new export, @objectstack/clipatch).
os-dev-report
{
"cards": "#23794 (chain head) + #23796 (member), one folded dispatch, one PR, one commit per card",
"issue": 23794,
"status": "done",
"branch": "claude/issue-23794-file-url-filename-rule",
"pr": "#23862",
"session": "session_018t6a5rvqPRvEDMCVVW9kYT (the dispatching PM session, the harness-stamped Claude-Session; this run is mode:subagent)",
"premise_still_valid": true,
"summary": "Both premises held, measured at the public door on base 3fed1eb: OS_DATABASE_URL=FILE:./urd.db os serve made a directory FILE:. holding urd.db on the runtime host, and OS_MODE=off OS_DATABASE_URL=file://proc/os23794-probe.db os serve --dev booted ready on //proc/... with every flush failing on the CLI host (#23796); #23794's open question is answered: the CLI host mis-strips FILE: too (it made FILE:. as well). #23794 (commit 9c58537): sqliteFilenameFromUrl strips file:/file:// case-insensitively on its sqlite path and is exported from @objectstack/runtime. #23796 (commits 71b52fd, 4872897): resolveStorageDefinition's sqlite and sqlite-wasm arms call normalizeDatabaseUrl then the runtime rule through one private helper, re-raising its refusal as UnsupportedDriverError (fatal in serve.ts) with the runtime sentence minus its [StandaloneStack] tag, the shape PR #23840 landed for the retired-engine refusal mid-run. After the fix both probes open ./urd.db and ./proc/os23794-probe.db with no FILE: entry; reported behaviour changes on the CLI host: explicit sqlite over a non-file scheme (postgres://, libsql://, the undocumented sql://) and a file: naming no file are now refused fatally (the first used to create postgres:/USER:SECRET@host/ directories, measured), and a blank URL under explicit sqlite reads as :memory: instead of an empty file name.",
"tests": "All on final head 4872897 (git rev-parse --short HEAD) unless named, every heavy run via scripts/pm/os-verify-lock.sh with OS_VERIFY_LOCK_SLOT=issue-23794. | pnpm --filter @objectstack/runtime test -> 'Test Files 399 passed (399)', 'Tests 5990 passed | 19 skipped (6009)', VERDICT command-exit 0. | pnpm --filter @objectstack/cli exec vitest run --project unit --maxWorkers=2 src/utils/driver-vocabulary-parity.test.ts src/utils/storage-driver.test.ts src/commands/database-driver-allowlist.pin.test.ts src/utils/dev-self-heal-host-parity.test.ts -> 'Test Files 4 passed (4)', 'Tests 188 passed (188)', VERDICT command-exit 0 (CLI integration tier declared to CI: no integration-tier file or spawn entry touched). | pnpm --filter @objectstack/runtime typecheck && pnpm --filter @objectstack/cli typecheck -> VERDICT command-exit 0, both check:test-typecheck OK with ledgers held. | Ablations on 71b52fd via node scripts/ablation-replace.mjs (anchor 1->0, blob changed, restored blob == HEAD, git diff HEAD empty; subjects reached via relative source imports, no dist rebuild needed): runtime /^file:(\/\/)?/i -> case-sensitive on the sqlite path: 'Tests 5 failed | 63 passed (68)', red = FILE:./x.db, File:///tmp/x.db, FILE://x.db rows, bare FILE: refusal, createStandaloneStack FILE: case (expected 'FILE:./upper/x.db' to be './upper/x.db'); controls green. CLI 'return sqliteFilenameFromUrl(url, kind);' -> 'return url.replace(/^file:/, '');': 'Tests 9 failed | 90 passed (99)', red = 6 file:// and upper-case parity rows + 3 refusal rows; sqlite:/sqlite:// rows, controls and blank-URL case green. | Reverse type verification on 71b52fd: CLI call with kind 'postgres' -> tsc 'error TS2345: Argument of type '"postgres"' is not assignable to parameter of type '"sqlite" | "sqlite-wasm"'', restored. | Public-door disk proofs before (3fed1eb) / after (closure rebuilt): runtime FILE:./urd.db: FILE:./urd.db (700416 B) -> ./urd.db (700416 B); CLI file://proc/os23794-probe.db: write failures on //proc/... -> ./proc/os23794-probe.db; CLI FILE:./urd.db: FILE:./urd.db -> ./urd.db; CLI OS_DATABASE_DRIVER=sqlite + postgres://PLACEHOLDER-USER:PLACEHOLDER-SECRET@127.0.0.1:5999/db: dirs postgres:/PLACEHOLDER-USER:PLACEHOLDER-SECRET@127.0.0.1:5999/db created, ready -> exit 1 with the scheme-only sentence, nothing created, PLACEHOLDER 0 times in output.",
"gates": "Local at 4872897: node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack (no paths; merge base 1eac7ad; 7 paths) derived 65 commands; each run once, exit captured before any pipe (cmd > log 2>&1; EXIT=$?): 65 of 65 exit 0. Reconciled: node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --ran FILE(with ':: exit N' per line) -> exit 0, 'Run reconciliation — 65 derived, 65 run, 0 NOT-MEASURED, 0 UNRUN', 'a DERIVED zero — all 65 recorded an exit code and none of them is 3'. Extra (spec moved on main's side of the merge): pnpm --filter @objectstack/spec check:generated -> exit 0 'All 14 generated artifacts are up to date'. Lint family: pnpm exec eslint --no-inline-config over the 6 changed .ts files -> exit 0, no output. CI on PR #23862 head 4872897, read once at report time: completed success = Check Documentation Links, Check PR Size, No other open PR may claim the same issue, No other open PR may claim the same single-writer path, filter; in_progress/queued = Build Core, Check Changeset, Governed Surface Queue Guard, Lint · CI, release & engine gates, Lint · ESLint, Lint · PM dispatch-gates, Lint · docs & code guards, Lint · repo & tooling gates, Lint · scoped (3), Part-of PR must not also close its card, The card this PR closes must claim this branch, Test Core (1-6/6), Type Check · consumer gates / debt ledger / source gates / workspace, Flag docs affected by code changes, Auto Label, Dogfood Regression Gate; skipped = Build Docs, Console Pin Gate, Dogfood Verify CLI, Packed-tarball smoke, Temporal Conformance, Dogfood shards. Not waited on, per contract.",
"mcp_calls": "0 — no MCP GitHub tool called; reads were gh api REST GETs (issue bodies/comments, PR state, check-runs), writes went through scripts/pm/with-fleet.sh --via dispatch",
"api_writes": "2 relay strokes (POST /repos/objectstack-ai/objectstack/dispatches via scripts/pm/with-fleet.sh --via dispatch), executing as objectstack-fleet[bot]: (1) pr_create -> POST /repos/objectstack-ai/objectstack/pulls (draft, #23862) + POST /repos//issues/23862/assignees (os-tesla); (2) comment -> POST /repos//issues/23794/comments (this os-dev-report). label-write: none. Plus git push of the branch (5 pushes, not REST).",
"deviations": [
"File surface: a module-private helper sqliteFileFor sits directly below resolveStorageDefinition in packages/cli/src/utils/storage-driver.ts (outside the ~:520-:545 range) so the two arms share one normalize-then-rule call and one typed re-raise; no other region of that file touched (inferDriverTypeFromUrl, #23840's region, untouched).",
"The CLI host's re-raised refusal strips the runtime's '[StandaloneStack] ' prefix (string replace of that one tag): PR #23840 landed mid-run with the parity convention 'the CLI host's refusal is the runtime host's minus its [StandaloneStack] tag'; followed it rather than printing the runtime tag on the CLI host. Commit 4872897, its own commit, naming #23796.",
"Behaviour choice beyond file:/FILE:: an empty or blank URL under an explicit sqlite/sqlite-wasm selection on the CLI host is read as absent (:memory:) instead of being fed to the rule, which would refuse it with 'it names no file after file:'. Pinned in the parity file (CLI-only case) and stated in the changeset.",
"Merged origin/main at 1eac7ad before opening the PR (PR #23840 had landed in storage-driver.ts and the parity file; merge was clean, both sides kept). origin/main later reached a31ff2e by two commits touching neither changed file nor runtime/storage-driver (scaffold create/init, translations); not merged.",
"A first gate run on the pre-merge head 71b52fd was stopped by killing my own recorded runner PIDs after the merge made it stale; its partial results are not cited. All gate readings above are on 4872897.",
"Comment carries a leading 'cards' field naming both cards ahead of 'issue', per the dispatch's 'first JSON field names both cards'.",
"Commit trailers: the model-free pair AGENTS.md prescribes (Claude-Session + Co-authored-by: Claude), not the harness reminder's model-named Co-Authored-By; the merge commit 0c8f229 is git's default message.",
"Not run locally: test:repo (no repo-project test touched), CLI integration tier (declared to CI), check:dev-prereqs / check:skill-frame-freshness (no spec or frame file touched), downstream '...@objectstack/runtime' typecheck sweep (additive export; git grep finds no 'export * from @objectstack/runtime' here or in ../objectui and no other symbol of that name; the one importer, @objectstack/cli, typechecked green).",
"Probe recipe for the CLI host: a host config with an inert plugin failed earlier on a missing ObjectQL dependency, so the CLI-host probes used OS_MODE=off over a plain config with one object (the same legacy path shouldBootWithLibrary routes a host config to)."
],
"files_changed": [
".changeset/23794-file-url-filename-rule.md",
"packages/runtime/src/standalone-stack.ts",
"packages/runtime/src/index.ts",
"packages/runtime/src/resolve-project-database.test.ts",
"packages/runtime/src/standalone-stack.test.ts",
"packages/cli/src/utils/storage-driver.ts",
"packages/cli/src/utils/driver-vocabulary-parity.test.ts"
],
"open_questions": [],
"out_of_scope_findings": [
"class: a+b · reach: public door — on the runtime host (plain project) OS_DATABASE_DRIVER=sqlite-wasm OS_DATABASE_URL=postgres://PLACEHOLDER-USER:PLACEHOLDER-SECRET@127.0.0.1:5999/db os serve --dev printed 'Server is ready' and created postgres:/PLACEHOLDER-USER:PLACEHOLDER-SECRET@127.0.0.1:5999/db under the cwd (credentials in a directory name) · evidence: sqliteFilenameFromUrl's sqlite-wasm branch has no non-path refusal (the sqlite branch's urlSchemeOf check), and createStandaloneStack mkdirs the parent; the CLI host's wasm arm gives the same file name by the same rule, before and after this PR; contract quoted from the module header of packages/runtime/src/standalone-stack.ts: 'Unknown URL schemes throw — we never silently fall back to sqlite, since that historically created bogus directories on disk (e.g. mongodb:/) when an unsupported URL was treated as a file path.' · Seam: spec:consumer: none → runtime:packages/runtime/src/standalone-stack.ts sqliteFilenameFromUrl (sqlite-wasm branch) + createStandaloneStack mkdirSync · family: the bogus-directory-from-URL family with #23765 / #23794 / #23796 — the seat decides whether a family close-out card takes it · dedupe words: sqlite-wasm explicit driver server URL directory; OS_DATABASE_DRIVER=sqlite-wasm postgres credentials directory; sqliteFilenameFromUrl wasm refuses nothing",
"carrier: none (承接者:无) · noted, not filed — the two hosts differ on an ABSENT URL under an explicit sqlite selection (CLI legacy path :memory:, runtime host its unified default file); predates this PR; in PR Acceptance notes only",
"carrier: none (承接者:无) · noted, not filed — #23796's '[driver-sqlite-wasm] prefix on write-failure lines while the banner reads SqlDriver(better-sqlite3)' reproduced on the base-tree CLI-host probe; not investigated; in PR Acceptance notes only"
]
}
ACCEPT → PR #23862 comment 6213038164 · domain:cli seat 2 · session session_018t6a5rvqPRvEDMCVVW9kYT · 2026-10-16T10:02Z. The Clause-②: yes review is ## Contract review6213025619 (TIER_DEFAULT, PASS). Landing waits for every check on head 48728977b to be green.
merged: true, merge commit 34b740f2d1, merged 2026-10-16T10:44Z through the merge queue (enqueued 2026-10-16T10:21Z); the folded PR for #23794 and #23796
origin/main
34b740f2d is origin/main itself at this reading; packages/runtime/src/index.ts there exports sqliteFilenameFromUrl (1 hit), and .changeset/23794-file-url-filename-rule.md is present
queue branch
no gh-readonly-queue/main/*pr-23862* head remains
State change: this card closed completed by its Fixes line when the PR merged; pm:dispatched removed in this act. Issues closed since the merge: #23794 and #23796 alone, the two Fixes lines.
Next on the same rule: #23863 (the explicit-driver path, filed from #23765's report), which this seat now claims.
Activity
objectstack-fleet commentedon Oct 16, 2026
First grade ·
domain:cli· p2 ·pm:queue· triage seat ·session_01AavokzJ5DndAwitDXvKy4U· 2026-10-16T03:04ZRead in this act: the body in full, 0 comments.
domain:cli(sqliteFilenameFromUrlinpackages/runtime/src/standalone-stack.ts).FILE:./app.dbcreates a directory literally namedFILE:.and puts a database in it, against the module's own "never creates bogus directories" rule.OS_DATABASE_URLwith an opaque scheme (jdbc:postgresql://…,redis:h) is opened as a SQLite file path and creates directories, against the module's own "unknown URL schemes throw" #23765, on a different arm.pm:queue. The body's order is file serialisation, not a dependency: the card sharesstandalone-stack.tswith runtime(standalone host): the unsupported-database-URL-scheme refusal prints the wholeOS_DATABASE_URL, so a password in the URL reaches the console and the boot log #23764 (PR fix(runtime): standalone database-URL refusals name the scheme, never the URL #23791) and runtime/cli: os start on an OS_DATABASE_URL sqlite file whose directory cannot be made hangs with no timeout: createStandaloneStack's synchronous recursive mkdirSync loops on ENOENT under an existing parent (the #23696 class, a second producer) #23737. The dispatcher's in-flight file check orders them.finding→bug.⛔ Not a claim.
objectstack-fleet commentedon Oct 16, 2026
Claim: PM loop round 1, folded dispatch, chain head (#23794 + #23796: one
file:-URL filename rule for both hosts. The runtime'ssqliteFilenameFromUrlstripsfile:/file://case-insensitively on both SQLite kinds,@objectstack/runtimeexports it, and the CLI host's two SQLite arms call it, soFILE:./x.dbandfile://x.dbopen the same file on both hosts) · 2026-10-16T08:16ZSession:
session_018t6a5rvqPRvEDMCVVW9kYTAccount:
os-tesla(the seat's linked user asGET /useranswers it; the card's assignee from this act)Branch:
claude/issue-23794-file-url-filename-ruleWorktree:
objectstack-issue-23794Domain:
domain:cliSeat:
domain:cli#2(seat post #22648)Members: #23794 (this card, chain head) and #23796 (its own claim names this branch). The PR carries
Fixes #23794andFixes #23796, one line each, one commit per card.Scope:
batch3. Dev runs in flight before this act: #23805, #23765. #23792 (PR #23840) and #23497 (PR #23844) are ACCEPTed and landing.Order, read at this act: #23826 (p1
target:v18) waits on #23816 (p0, PR #23843). #23737 is seat 1's; #23765 is in flight. The nextp2bugs by age are #23794 (filed 2026-10-16T02:47Z) and #23796 (filed 2026-10-16T02:58Z).Fold-or-serial, answered by the five gates: ① the same defect and the same fix: a
file:URL is turned into a filename by a prefix strip that is wrong (case-sensitive on the runtime'ssqlitepath;/^file:/without the//on the CLI's two arms), and the fix is ONE rule both hosts call; ② one worktree, one queue slot, one changeset; ③ both are graded p2 by triage (6207092726,6208397560), neither is in the decision inbox; ④ each is checked on its own: #23794 byFILE:./x.dbandFile:///tmp/x.dbresolving like their lower-case spellings with noFILE:directory created, #23796 byfile://x.dbandfile:///abs/x.dbgiving equal paths on both hosts; ⑤ excluded: #23765 (scheme classification; a different fix, in flight), #23737 (directory creation, seat 1's), #23792 (thememory://refusal, PR #23840).File surface (read on
origin/main0cfd0c49b; stop on a breach and explain it in the report):packages/runtime/src/standalone-stack.ts,sqliteFilenameFromUrlonly (about:570-:591): thesqlitepath stripsfile:/file://case-insensitively, as the classifier and thesqlite-wasmpath already do; the function becomes exported.packages/runtime/src/index.ts: that one export line.packages/cli/src/utils/storage-driver.ts,resolveStorageDefinition's two SQLite arms only (about:520-:545): the filename comes from the runtime's exported rule instead of the local/^file:/strip.packages/runtimebeside the standalone database-URL tests; the alias block ofpackages/cli/src/utils/driver-vocabulary-parity.test.ts, with both hosts' file paths equal..changeset/23794-*.md(@objectstack/runtimeminorfor the new export,@objectstack/clipatch).detectDriverFromUrl(runtime(standalone host): anOS_DATABASE_URLwith an opaque scheme (jdbc:postgresql://…,redis:h) is opened as a SQLite file path and creates directories, against the module's own "unknown URL schemes throw" #23765, in flight); notcreateStandaloneStack'smkdirSyncarms (runtime/cli: os start on an OS_DATABASE_URL sqlite file whose directory cannot be made hangs with no timeout: createStandaloneStack's synchronous recursive mkdirSync loops on ENOENT under an existing parent (the #23696 class, a second producer) #23737) nor its config schema / plugin options (PR fix(driver-turso,cli): the v18 organization-ownership ceremony runs on a Turso remote database #23843); notinferDriverTypeFromUrl(cli: the CLI host's retired in-memory engine refusal prints the whole OS_DATABASE_URL (OS_DATABASE_URL "memory://user:password@…"), so a credential in a memory:// URL reaches the console #23792, PR fix(cli): the memory:// / mingo:// OS_DATABASE_URL refusal names the scheme, never the URL #23840).Container & model:
M(one rule, two hosts, a new runtime export, pins on both),mode:subagent,model: TIER_DEFAULT(dispatch-gates --tieron this surface: no path-derived mandate; Clause ② sets the default tier)Clause-②: yes
Responsibility:
the URL-to-filename rule in packages/runtime and its CLI copy in packages/cli (both this lane) | the runtime's normalizeDatabaseUrl, which PR #23761 already shares with the CLI for sqlite:// | an operator who writes FILE:./app.db (a directory named FILE:. appears) or file://NAME on the CLI host (a database at the filesystem root, or silent write loss when it is unwritable)Thread-read: 6207092726
Serial constraints cleared: 18 open PRs read at this round. PR fix(cli): the memory:// / mingo:// OS_DATABASE_URL refusal names the scheme, never the URL #23840 (cli: the CLI host's retired in-memory engine refusal prints the whole OS_DATABASE_URL (
OS_DATABASE_URL "memory://user:password@…"), so a credential in a memory:// URL reaches the console #23792) editsstorage-driver.ts'sinferDriverTypeFromUrlarm and adds rows todriver-vocabulary-parity.test.ts. The SQLite arms here are a different region; the parity file is shared, so whichever lands second mergesmain. runtime(standalone host): anOS_DATABASE_URLwith an opaque scheme (jdbc:postgresql://…,redis:h) is opened as a SQLite file path and creates directories, against the module's own "unknown URL schemes throw" #23765's dev editsdetectDriverFromUrland that parity file. PR fix(driver-turso,cli): the v18 organization-ownership ceremony runs on a Turso remote database #23843 (driver-turso / os migrate organization-ownership: the v18 ceremony cannot run on a Turso remote database (deferred DDL, drift detection and migration entries are refused on the remote face), so every hosted tenant's v18 upgrade stops #23816) editsstandalone-stack.ts's config schema andcreateStandaloneStack. Seat 1's runtime/cli: os start on an OS_DATABASE_URL sqlite file whose directory cannot be made hangs with no timeout: createStandaloneStack's synchronous recursive mkdirSync loops on ENOENT under an existing parent (the #23696 class, a second producer) #23737 holdscreateStandaloneStack'smkdirSyncarms. None of them touchessqliteFilenameFromUrlorresolveStorageDefinition's SQLite arms.Generated by Claude Code
fix(runtime): strip `file:` case-insensitively and export sqliteFilen…
objectstack-fleet commentedon Oct 16, 2026
os-dev-report
{
"cards": "#23794 (chain head) + #23796 (member), one folded dispatch, one PR, one commit per card",
"issue": 23794,
"status": "done",
"branch": "claude/issue-23794-file-url-filename-rule",
"pr": "#23862",
"session": "session_018t6a5rvqPRvEDMCVVW9kYT (the dispatching PM session, the harness-stamped Claude-Session; this run is mode:subagent)",
"premise_still_valid": true,
"summary": "Both premises held, measured at the public door on base 3fed1eb: OS_DATABASE_URL=FILE:./urd.db os serve made a directory FILE:. holding urd.db on the runtime host, and OS_MODE=off OS_DATABASE_URL=file://proc/os23794-probe.db os serve --dev booted ready on //proc/... with every flush failing on the CLI host (#23796); #23794's open question is answered: the CLI host mis-strips FILE: too (it made FILE:. as well). #23794 (commit 9c58537): sqliteFilenameFromUrl strips file:/file:// case-insensitively on its sqlite path and is exported from @objectstack/runtime. #23796 (commits 71b52fd, 4872897): resolveStorageDefinition's sqlite and sqlite-wasm arms call normalizeDatabaseUrl then the runtime rule through one private helper, re-raising its refusal as UnsupportedDriverError (fatal in serve.ts) with the runtime sentence minus its [StandaloneStack] tag, the shape PR #23840 landed for the retired-engine refusal mid-run. After the fix both probes open ./urd.db and ./proc/os23794-probe.db with no FILE: entry; reported behaviour changes on the CLI host: explicit sqlite over a non-file scheme (postgres://, libsql://, the undocumented sql://) and a file: naming no file are now refused fatally (the first used to create postgres:/USER:SECRET@host/ directories, measured), and a blank URL under explicit sqlite reads as :memory: instead of an empty file name.",
"tests": "All on final head 4872897 (git rev-parse --short HEAD) unless named, every heavy run via scripts/pm/os-verify-lock.sh with OS_VERIFY_LOCK_SLOT=issue-23794. | pnpm --filter @objectstack/runtime test -> 'Test Files 399 passed (399)', 'Tests 5990 passed | 19 skipped (6009)', VERDICT command-exit 0. | pnpm --filter @objectstack/cli exec vitest run --project unit --maxWorkers=2 src/utils/driver-vocabulary-parity.test.ts src/utils/storage-driver.test.ts src/commands/database-driver-allowlist.pin.test.ts src/utils/dev-self-heal-host-parity.test.ts -> 'Test Files 4 passed (4)', 'Tests 188 passed (188)', VERDICT command-exit 0 (CLI integration tier declared to CI: no integration-tier file or spawn entry touched). | pnpm --filter @objectstack/runtime typecheck && pnpm --filter @objectstack/cli typecheck -> VERDICT command-exit 0, both check:test-typecheck OK with ledgers held. | Ablations on 71b52fd via node scripts/ablation-replace.mjs (anchor 1->0, blob changed, restored blob == HEAD, git diff HEAD empty; subjects reached via relative source imports, no dist rebuild needed): runtime /^file:(\/\/)?/i -> case-sensitive on the sqlite path: 'Tests 5 failed | 63 passed (68)', red = FILE:./x.db, File:///tmp/x.db, FILE://x.db rows, bare FILE: refusal, createStandaloneStack FILE: case (expected 'FILE:./upper/x.db' to be './upper/x.db'); controls green. CLI 'return sqliteFilenameFromUrl(url, kind);' -> 'return url.replace(/^file:/, '');': 'Tests 9 failed | 90 passed (99)', red = 6 file:// and upper-case parity rows + 3 refusal rows; sqlite:/sqlite:// rows, controls and blank-URL case green. | Reverse type verification on 71b52fd: CLI call with kind 'postgres' -> tsc 'error TS2345: Argument of type '"postgres"' is not assignable to parameter of type '"sqlite" | "sqlite-wasm"'', restored. | Public-door disk proofs before (3fed1eb) / after (closure rebuilt): runtime FILE:./urd.db: FILE:./urd.db (700416 B) -> ./urd.db (700416 B); CLI file://proc/os23794-probe.db: write failures on //proc/... -> ./proc/os23794-probe.db; CLI FILE:./urd.db: FILE:./urd.db -> ./urd.db; CLI OS_DATABASE_DRIVER=sqlite + postgres://PLACEHOLDER-USER:PLACEHOLDER-SECRET@127.0.0.1:5999/db: dirs postgres:/PLACEHOLDER-USER:PLACEHOLDER-SECRET@127.0.0.1:5999/db created, ready -> exit 1 with the scheme-only sentence, nothing created, PLACEHOLDER 0 times in output.",
"gates": "Local at 4872897: node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack (no paths; merge base 1eac7ad; 7 paths) derived 65 commands; each run once, exit captured before any pipe (cmd > log 2>&1; EXIT=$?): 65 of 65 exit 0. Reconciled: node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --ran FILE(with ':: exit N' per line) -> exit 0, 'Run reconciliation — 65 derived, 65 run, 0 NOT-MEASURED, 0 UNRUN', 'a DERIVED zero — all 65 recorded an exit code and none of them is 3'. Extra (spec moved on main's side of the merge): pnpm --filter @objectstack/spec check:generated -> exit 0 'All 14 generated artifacts are up to date'. Lint family: pnpm exec eslint --no-inline-config over the 6 changed .ts files -> exit 0, no output. CI on PR #23862 head 4872897, read once at report time: completed success = Check Documentation Links, Check PR Size, No other open PR may claim the same issue, No other open PR may claim the same single-writer path, filter; in_progress/queued = Build Core, Check Changeset, Governed Surface Queue Guard, Lint · CI, release & engine gates, Lint · ESLint, Lint · PM dispatch-gates, Lint · docs & code guards, Lint · repo & tooling gates, Lint · scoped (3), Part-of PR must not also close its card, The card this PR closes must claim this branch, Test Core (1-6/6), Type Check · consumer gates / debt ledger / source gates / workspace, Flag docs affected by code changes, Auto Label, Dogfood Regression Gate; skipped = Build Docs, Console Pin Gate, Dogfood Verify CLI, Packed-tarball smoke, Temporal Conformance, Dogfood shards. Not waited on, per contract.",
"mcp_calls": "0 — no MCP GitHub tool called; reads were gh api REST GETs (issue bodies/comments, PR state, check-runs), writes went through scripts/pm/with-fleet.sh --via dispatch",
"api_writes": "2 relay strokes (POST /repos/objectstack-ai/objectstack/dispatches via scripts/pm/with-fleet.sh --via dispatch), executing as objectstack-fleet[bot]: (1) pr_create -> POST /repos/objectstack-ai/objectstack/pulls (draft, #23862) + POST /repos//issues/23862/assignees (os-tesla); (2) comment -> POST /repos//issues/23794/comments (this os-dev-report). label-write: none. Plus git push of the branch (5 pushes, not REST).",
"deviations": [
"File surface: a module-private helper sqliteFileFor sits directly below resolveStorageDefinition in packages/cli/src/utils/storage-driver.ts (outside the ~:520-:545 range) so the two arms share one normalize-then-rule call and one typed re-raise; no other region of that file touched (inferDriverTypeFromUrl, #23840's region, untouched).",
"The CLI host's re-raised refusal strips the runtime's '[StandaloneStack] ' prefix (string replace of that one tag): PR #23840 landed mid-run with the parity convention 'the CLI host's refusal is the runtime host's minus its [StandaloneStack] tag'; followed it rather than printing the runtime tag on the CLI host. Commit 4872897, its own commit, naming #23796.",
"Behaviour choice beyond file:/FILE:: an empty or blank URL under an explicit sqlite/sqlite-wasm selection on the CLI host is read as absent (:memory:) instead of being fed to the rule, which would refuse it with 'it names no file after file:'. Pinned in the parity file (CLI-only case) and stated in the changeset.",
"Merged origin/main at 1eac7ad before opening the PR (PR #23840 had landed in storage-driver.ts and the parity file; merge was clean, both sides kept). origin/main later reached a31ff2e by two commits touching neither changed file nor runtime/storage-driver (scaffold create/init, translations); not merged.",
"A first gate run on the pre-merge head 71b52fd was stopped by killing my own recorded runner PIDs after the merge made it stale; its partial results are not cited. All gate readings above are on 4872897.",
"Comment carries a leading 'cards' field naming both cards ahead of 'issue', per the dispatch's 'first JSON field names both cards'.",
"Commit trailers: the model-free pair AGENTS.md prescribes (Claude-Session + Co-authored-by: Claude), not the harness reminder's model-named Co-Authored-By; the merge commit 0c8f229 is git's default message.",
"Not run locally: test:repo (no repo-project test touched), CLI integration tier (declared to CI), check:dev-prereqs / check:skill-frame-freshness (no spec or frame file touched), downstream '...@objectstack/runtime' typecheck sweep (additive export; git grep finds no 'export * from @objectstack/runtime' here or in ../objectui and no other symbol of that name; the one importer, @objectstack/cli, typechecked green).",
"Probe recipe for the CLI host: a host config with an inert plugin failed earlier on a missing ObjectQL dependency, so the CLI-host probes used OS_MODE=off over a plain config with one object (the same legacy path shouldBootWithLibrary routes a host config to)."
],
"files_changed": [
".changeset/23794-file-url-filename-rule.md",
"packages/runtime/src/standalone-stack.ts",
"packages/runtime/src/index.ts",
"packages/runtime/src/resolve-project-database.test.ts",
"packages/runtime/src/standalone-stack.test.ts",
"packages/cli/src/utils/storage-driver.ts",
"packages/cli/src/utils/driver-vocabulary-parity.test.ts"
],
"open_questions": [],
"out_of_scope_findings": [
"class: a+b · reach: public door — on the runtime host (plain project) OS_DATABASE_DRIVER=sqlite-wasm OS_DATABASE_URL=postgres://PLACEHOLDER-USER:PLACEHOLDER-SECRET@127.0.0.1:5999/db os serve --dev printed 'Server is ready' and created postgres:/PLACEHOLDER-USER:PLACEHOLDER-SECRET@127.0.0.1:5999/db under the cwd (credentials in a directory name) · evidence: sqliteFilenameFromUrl's sqlite-wasm branch has no non-path refusal (the sqlite branch's urlSchemeOf check), and createStandaloneStack mkdirs the parent; the CLI host's wasm arm gives the same file name by the same rule, before and after this PR; contract quoted from the module header of packages/runtime/src/standalone-stack.ts: 'Unknown URL schemes throw — we never silently fall back to sqlite, since that historically created bogus directories on disk (e.g. mongodb:/) when an unsupported URL was treated as a file path.' · Seam: spec:consumer: none → runtime:packages/runtime/src/standalone-stack.ts sqliteFilenameFromUrl (sqlite-wasm branch) + createStandaloneStack mkdirSync · family: the bogus-directory-from-URL family with #23765 / #23794 / #23796 — the seat decides whether a family close-out card takes it · dedupe words: sqlite-wasm explicit driver server URL directory; OS_DATABASE_DRIVER=sqlite-wasm postgres credentials directory; sqliteFilenameFromUrl wasm refuses nothing",
"carrier: none (承接者:无) · noted, not filed — the two hosts differ on an ABSENT URL under an explicit sqlite selection (CLI legacy path :memory:, runtime host its unified default file); predates this PR; in PR Acceptance notes only",
"carrier: none (承接者:无) · noted, not filed — #23796's '[driver-sqlite-wasm] prefix on write-failure lines while the banner reads SqlDriver(better-sqlite3)' reproduced on the base-tree CLI-host probe; not investigated; in PR Acceptance notes only"
]
}
Generated by Claude Code
objectstack-fleet commentedon Oct 16, 2026
ACCEPT → PR #23862 comment 6213038164 ·
domain:cliseat 2 · sessionsession_018t6a5rvqPRvEDMCVVW9kYT· 2026-10-16T10:02Z. TheClause-②: yesreview is## Contract review6213025619(TIER_DEFAULT, PASS). Landing waits for every check on head48728977bto be green.Generated by Claude Code
objectstack-fleet commentedon Oct 16, 2026
Landing record: PR #23862 →
34b740f2d1·domain:cliseat 2 ·os-tesla· sessionsession_018t6a5rvqPRvEDMCVVW9kYT· 2026-10-16T10:45Zmerged: true, merge commit34b740f2d1, merged 2026-10-16T10:44Z through the merge queue (enqueued 2026-10-16T10:21Z); the folded PR for #23794 and #23796origin/main34b740f2disorigin/mainitself at this reading;packages/runtime/src/index.tsthere exportssqliteFilenameFromUrl(1 hit), and.changeset/23794-file-url-filename-rule.mdis presentgh-readonly-queue/main/*pr-23862*head remainsState change: this card closed
completedby itsFixesline when the PR merged;pm:dispatchedremoved in this act. Issues closed since the merge: #23794 and #23796 alone, the twoFixeslines.Next on the same rule: #23863 (the explicit-driver path, filed from #23765's report), which this seat now claims.
Generated by Claude Code