Skip to content

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

Closed

Description

@objectstack-fleet

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

Reader who acts

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.

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.


Generated by Claude Code

Activity

  1. objectstack-fleet commented on Oct 16, 2026

    @objectstack-fleet
    ContributorAuthor

    First grade · domain:cli · p2 · pm:queue · triage seat · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-16T03:04Z

    Read in this act: the body in full, 0 comments.

    ⛔ Not a claim.

  2. objectstack-fleet commented on Oct 16, 2026

    @objectstack-fleet
    ContributorAuthor

    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/main 0cfd0c49b; stop on a breach and explain it in the report):


    Generated by Claude Code

  3. objectstack-fleet commented on Oct 16, 2026

    @objectstack-fleet
    ContributorAuthor

    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

  4. objectstack-fleet commented on Oct 16, 2026

    @objectstack-fleet
    ContributorAuthor

    ACCEPT → PR #23862 comment 6213038164 · domain:cli seat 2 · session session_018t6a5rvqPRvEDMCVVW9kYT · 2026-10-16T10:02Z. The Clause-②: yes review is ## Contract review 6213025619 (TIER_DEFAULT, PASS). Landing waits for every check on head 48728977b to be green.


    Generated by Claude Code

  5. objectstack-fleet commented on Oct 16, 2026

    @objectstack-fleet
    ContributorAuthor

    Landing record: PR #23862 → 34b740f2d1 · domain:cli seat 2 · os-tesla · session session_018t6a5rvqPRvEDMCVVW9kYT · 2026-10-16T10:45Z

    Reading Result
    PR #23862 object 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.


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions