Skip to content

fix(cli): the memory:// / mingo:// OS_DATABASE_URL refusal names the scheme, never the URL - #23840

Merged
objectstack-fleet[bot] merged 2 commits into
mainfrom
claude/issue-23792-cli-memory-url-redact
Oct 16, 2026
Merged

objectstack-fleet[bot] merged 2 commits into
mainfrom
claude/issue-23792-cli-memory-url-redact

Conversation

@objectstack-fleet

@objectstack-fleet objectstack-fleet Bot commented Oct 16, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #23792

Clause-②: no

What changes

inferDriverTypeFromUrl in packages/cli/src/utils/storage-driver.ts refuses a memory:// or mingo:// OS_DATABASE_URL (the retired in-memory engine). Its refusal was built from the whole URL, OS_DATABASE_URL "URL", and os serve prints that message as it exits 1. Both schemes accept anything after the //, so a user:password@ and an ?authToken= were printed to the console.

The arm now names the scheme only, in the runtime host's words: An OS_DATABASE_URL with the "memory://" scheme selects the in-memory (mingo) engine, .... The rest of the sentence (the SQLite replacements) comes from the shared retiredMemoryEngineMessage, unchanged. The UnsupportedDriverError it throws now carries the scheme as driverType, not the URL, as the unrecognised-scheme arm below it already does.

Landing: the memory / mingo arm only, as the claim's file surface names it. No other arm, the OS_DATABASE_DRIVER / --database-driver arm, packages/runtime and the scheme parsing are untouched.

Why the words are mirrored, not imported

The runtime phrase is built inside refuseRetiredMemoryEngine in packages/runtime/src/standalone-stack.ts, and it is module-local: @objectstack/runtime exports retiredMemoryEngineMessage (the shared tail, already used here) but not the subject. The dispatch rules out a new export from packages/runtime on this card, so the CLI arm writes the subject out. A parity row in driver-vocabulary-parity.test.ts holds the two hosts' refusals equal for the same credentialed URL (the CLI's is the runtime's minus its [StandaloneStack] tag), so the copy cannot drift silently.

Reproduction at the public door

Built CLI, run from examples/app-todo, the URL carrying placeholder credentials only:

OS_MODE=off OS_DATABASE_URL='SCHEME://PLACEHOLDER-USER:PLACEHOLDER-SECRET@127.0.0.1:6399/0?authToken=PLACEHOLDER-TOKEN' node ../../packages/cli/bin/run.js serve -p PORT
memory:// mingo://
base 1ecb08a1cc exit 1; PLACEHOLDER-USER / -SECRET / -TOKEN printed 1 / 1 / 1 time exit 1; 1 / 1 / 1
this branch (CLI built from 3ddd364ad) exit 1; 0 / 0 / 0, and 127.0.0.1:6399 0 exit 1; 0 / 0 / 0, and 127.0.0.1:6399 0
  • Before: ✗ OS_DATABASE_URL "memory://PLACEHOLDER-USER:PLACEHOLDER-SECRET@127.0.0.1:6399/0?authToken=PLACEHOLDER-TOKEN" selects the in-memory (mingo) engine, ...
  • After: ✗ An OS_DATABASE_URL with the "memory://" scheme selects the in-memory (mingo) engine, ... (and "mingo://" for the other scheme).

Pins

packages/cli/src/utils/storage-driver.test.ts:

  • The placeholder pin. A memory:// and a mingo:// URL carrying a placeholder user, password and token: the refusal is an UnsupportedDriverError with recognized: false and driverType equal to the scheme; its message names the scheme, --fresh and :memory:; neither the message nor driverType contains any of the three placeholders (nor the host).
  • CONTROL. The same credentialed tail under postgres://, postgresql://, pg://, mysql://, mysql2://, mongodb://, mongodb+srv://, libsql:// and wasm-sqlite:// classifies as before. The existing "maps each recognized URL scheme" and unrecognised-scheme rows are unchanged and green.
  • The existing memory-scheme row asserted the whole URL appeared in the message (memory://ignored-host, MINGO://x). It now asserts the scheme ("memory://", "MINGO://") and driverType.

packages/cli/src/utils/driver-vocabulary-parity.test.ts: for a credentialed memory:// and mingo:// URL, both hosts refuse, name the scheme, print none of the placeholders, and the CLI's message equals the runtime's minus [StandaloneStack] .

Tests (local)

  • pnpm --filter @objectstack/cli exec vitest run --project unit --maxWorkers=2 on a1a28595e: Test Files 297 passed (297), Tests 4447 passed (4447), lock VERDICT command-exit 0. It ran longer than one foreground call on this shared box (13m53s under the lock), so it was started detached under the lock while the derived gates ran in the foreground; its result was read from the lock's VERDICT line after it exited.
  • The two edited files alone, --project unit (both are unit-tier): Test Files 2 passed (2), Tests 162 passed (162).
  • pnpm --filter @objectstack/cli typecheck on a1a28595e: exit 0; check:test-typecheck: OK (the test layer compiles under tsconfig.test.json).
  • integration tier: declared to CI. The diff touches no integration-tier file and no spawn entry.

Ablation (one-time, nothing kept)

The tests import ./storage-driver.js relatively, so they read the source and no rebuild is involved. Each leg through node scripts/ablation-replace.mjs (anchor hit 1 to 0, blob changed, then restored to the HEAD blob 74287da383 with git diff HEAD empty):

  1. Subject back to the old OS_DATABASE_URL "${u}": 6 failed / 156 passed. Red: the two placeholder pins, the two parity rows, and the memory://ignored-host / MINGO://x scheme rows, each on the "names the scheme" assertion.
  2. Scheme kept but the URL appended (... "${retiredScheme}" scheme (${u})), so the placeholder assertions are the first to fail: 4 failed / 158 passed, all four on not to contain 'PLACEHOLDER-USER' (both placeholder pins, both parity rows).
  3. driverType back to the URL (u): 4 failed / 158 passed, on expected 'memory://PLACEHOLDER-USER:...' to be 'memory://' and the two scheme rows.

Gates

  • node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack on a1a28595e (merge base 43567a8fc, 4 paths, 121 changed lines): 64 commands. Reconciled with --ran: 64 derived famil(ies) accounted for — 62 run, 2 NOT-MEASURED.
    • 62 exit 0.
    • NOT MEASURED: check:dual-build-cjs-loads and check:i18n-coverage, both exit 3 PREREQUISITE NOT MET (packages outside the CLI's build closure have no dist/ here). CI's Lint & Repo Gates runs both.
  • pnpm exec eslint --no-inline-config over the three edited .ts files: exit 0. The repo-wide lint is CI's Lint & Repo Gates.
  • Control-byte self-scan of the four changed files: no match.

Acceptance notes

The Tests section's account of the detached unit run was corrected by the domain:cli seat 2 PM (session session_018t6a5rvqPRvEDMCVVW9kYT) at review, from the dev report's deviation 1.

…e URL

inferDriverTypeFromUrl's retired in-memory engine arm built its refusal
from the whole OS_DATABASE_URL, so a user, password or token in a
memory:// or mingo:// URL was printed when `os serve` exited. The arm now
names the scheme in the runtime host's words ("An OS_DATABASE_URL with the
"memory://" scheme"), and carries the scheme, not the URL, as driverType.

Pins: a credentialed memory:// and mingo:// URL is refused naming the
scheme and the SQLite replacements and none of the placeholders; the same
tail under every other scheme classifies as before; both hosts refuse it
in the same words.

Claude-Session: https://claude.ai/code/session_018t6a5rvqPRvEDMCVVW9kYT
Co-authored-by: Claude <noreply@anthropic.com>
@github-actions github-actions Bot added size/m documentation Improvements or additions to documentation tests tooling labels Oct 16, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

1 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
  • the SDK route bridge reached 54 of 206 client-bound route-ledger rows — the other 152 have no registrar path: tail to select them, so pages documenting THEIR client methods cannot appear above, on this or any run. Of those 152: 0 are remediable by widening that discovery convention (an in-repo file declares the path; the convention did not scan it); 55 are structural — on a ledger where NOT ONE row is declared in-repo, so no discovery change reaches them at any price; 97 are undecided (no in-repo declaration, on a ledger that has other in-repo registrars — absence and an unreadable spelling are not distinguishable here). The rows themselves: node scripts/docs-audit/affected-docs.mjs --bridge-coverage
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.
  • a key NAME is not a key, so the hand re-read the line above prescribes can land on the wrong schema. The same spelling is authorable on one governed type and a [REMOVED] tombstone on another for each of active, aria, joins, objects, template, tools and version (censused on [finding] tools is a key on BOTH AgentSchema (tombstoned, dead) and SkillSchema (live, cloud-attested), so a name-based search attributes skill examples to the agent key — it produced a false stop-the-line alarm on PR #19059 #19093 over the liveness ledger's governed types, top-level keys); nothing in a search result distinguishes the two, so a grep hit on a LIVE example reads as evidence about the DEAD key. Measured on fix(spec): the agent.tools liveness row says dead — it claimed live on a key the schema tombstoned #19059: content/docs/ai/agents.mdx was reported as contradicting the agent.tools tombstone over its tools: example at :161, which is inside the defineSkill({ block opened at :155 — the page was already correct. Settle ownership by PARSING the value against both schemas, never by the name: that literal PASSES SkillSchema, and as an AgentSchema it FAILS at tools with the tombstone prescription. ⛔ These names are not the whole class — a key retired through a .strict() guidance map leaves no tombstone in the walked shape and none of them here (tool.category, live as AIToolDefinition.category).

Coarse fallback — 28 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json 0cfd0c49bd2635da048fae96b35a38448141fa9d → packageMentionDocs.

Which tree this was computed on

This run read content/docs from 5adeeb3350473a9bc81ebc9a4fe14acf3127d7d0 — the merge of head a1a28595ef615c20cdcedcc5adcd91db538586b2 into base 0cfd0c49bd2635da048fae96b35a38448141fa9d, which is what actions/checkout gives a pull_request run. Not the PR head.

A worktree cut from an older main holds a different content/docs, so re-deriving there can legitimately return a different list — that is a different tree, not a wrong row. To answer on the same tree:

# while this PR is open — GitHub drops the merge commit once it closes
git fetch origin 5adeeb3350473a9bc81ebc9a4fe14acf3127d7d0 && git checkout 5adeeb3350473a9bc81ebc9a4fe14acf3127d7d0
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 0cfd0c49bd2635da048fae96b35a38448141fa9d a1a28595ef615c20cdcedcc5adcd91db538586b2 && git checkout -B drift-repro 0cfd0c49bd2635da048fae96b35a38448141fa9d && git merge --no-ff a1a28595ef615c20cdcedcc5adcd91db538586b2

node scripts/docs-audit/affected-docs.mjs --json 0cfd0c49bd2635da048fae96b35a38448141fa9d

⚠️ That checkout carried uncommitted changes, so the commit above does not fully identify what was read.

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

席位核对

ACCEPT · #23792 · domain:cli seat 2 · os-tesla · session session_018t6a5rvqPRvEDMCVVW9kYT · 2026-10-16T08:08Z · reviewed head a1a28595ef615c20cdcedcc5adcd91db538586b2, against GitHub and origin/main, not against the report's prose.

  1. Shape. Draft, base main, first line Fixes #23792; the only closing keyword in the body is that one (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 / cli(storage): OS_DATABASE_URL=file://NAME opens //NAME at the filesystem root on the CLI host, where the runtime host opens ./NAME (the file: twin of the sqlite:// alias #23633 fixed) #23796 are named in a non-closing sentence). Clause-②: no at line start in the body and in the changeset, matching the claim. Files: storage-driver.ts, storage-driver.test.ts, driver-vocabulary-parity.test.ts, .changeset/23792-memory-url-refusal-no-url.md: inside the claim's surface (the parity file is the "sibling test file" it allows). check-governed-merges --pr 23840: 0 of 4 paths governed; 121 changed lines. No review face: Clause-②: no with no narrowing arm, no packages/spec, no governed path.
  2. Premise, measured. On origin/main, storage-driver.ts built the refusal over the raw URL (the triage unlock's reading, line :334). The diff replaces both the message subject and the UnsupportedDriverError's driverType with the scheme. driverType has no reader outside the constructor in packages/cli/src and packages/runtime/src (non-test, read on the PR head), so the value change moves no behaviour. The report's door reproduction (placeholders 1/1/1 on base, 0/0/0 after) is in the body; the three-leg ablation is reported, each leg on its own anchor.
  3. Changeset, sentence by sentence. @objectstack/cli patch, a published package. "the os serve path a host config takes … and the one OS_MODE=off|none|legacy takes": shouldBootWithLibrary (packages/cli/src/utils/plugin-detection.ts) returns false for a host config and for those three modes, and that path reaches resolveDriverType (serve.ts about :3140). "os dev and os start reach it through their serve child": dev.ts :680 and start.ts :490 spawn serve. "the runtime host's words": the new parity row asserts the CLI message equals the runtime's minus [StandaloneStack] . FROM / TO and "What does not change" match the diff.
  4. Gates, pinned to the head. a1a28595ef check-runs read at review: 37; 24 success, 6 skipped (push-only or opt-in jobs), 7 in_progress (Test Core 1–4/6, Type Check · consumer gates, Lint · repo & tooling gates, Lint · docs & code guards). Landing waits for every check green or expected-skipped; this record is not a green reading. The dev's local subset (cli unit 297 files / 4447 tests, typecheck, 62 of 64 derived gate commands, check:dual-build-cjs-loads and check:i18n-coverage NOT MEASURED for a missing dist/) is on that head; CI is the authority for the two.
  5. Accepted deviations. (1) The body's Tests section said the full unit run was "waited on with a foreground tail --pid"; it was read from the lock's VERDICT line after exit. The seat corrected that sentence in the body (relay run 38871568328). (2) One parity row added in a sibling test file, for the card's "same words" requirement. (3) Three ablation legs instead of one. (4) A merge of origin/main (43567a8fc, scripts/ci only) before the PR opened.
  6. Out of scope. The report's one finding: the TSDoc of retiredMemoryEngineMessage (packages/runtime/src/resolve-project-database.ts) still gives The database URL "memory://" as an example subject. A comment that no behaviour reads, outside the three filing classes: Acceptance notes (it is in the PR's notes), not filed.

Landing: once every check on the head is green or an expected skip, this seat flips the PR ready and arms auto-merge through the relay, then follows it to MERGED.


Generated by Claude Code

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review October 16, 2026 08:20
@objectstack-fleet
objectstack-fleet Bot enabled auto-merge October 16, 2026 08:20
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Oct 16, 2026
Merged via the queue into main with commit 66d456d Oct 16, 2026
48 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/issue-23792-cli-memory-url-redact branch October 16, 2026 08:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/m tests tooling

Projects

None yet

2 participants