Repository navigation
fix(spec,runtime,cli)!: the in-memory engine is no longer a boot store — every boot door refuses it and names SQLite instead - #21598
Conversation
…tion face (A1 red-set probe) Spec row edit only, for the dispatch's A1 red-set measurement. Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YDt3PzwfrkuFzUBF89WPmM
…door The spec row (d480ef0) withdrew memory, mingo and in-memory from the driver vocabulary's selection face. This commit lands both hosts' halves: - runtime: the memory-driver rung of resolveProjectDatabaseUrl becomes a refusal ahead of every rung; the standalone stack's URL detection recognises memory:// and mingo:// and refuses them, naming the source; StandaloneDatabaseDriverSchema enumerates the selection face; the dispatch loses its memory arm. One sentence, retiredMemoryEngineMessage, names the SQLite replacements (os dev --fresh, or :memory:). - cli: inferDriverTypeFromUrl refuses memory:// and mingo://; resolveStorageDefinition refuses the spellings with the same sentence; the memory definition arm is gone; help, notes and the flag doc follow. - tests: the red pins rewritten to pin the refusals; the parity pin gains the withdrawn-spelling and URL-door rows; the runtime boots move to SQLite :memory:; the no_sql_seam test drives a seam double. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016GiHYRmLSNWTfbX9gVQkpz
…r the in-memory engine's retirement - docs: cli.mdx, environment-variables.mdx, data-modeling/drivers.mdx and plugins/index.mdx stop offering the engine as a boot store and name the SQLite replacements; the spec row's stale doc comments are rewritten. - QA: cli.dev-boot-contract and cli.migrate-duplicates-inventory follow the retirement (the no_sql_seam negative cites the seam-double pin); cli.build-own-contract's exit-2 wording names this.exit(2). - scripts/driver-memory-census.ledger.json: the CLI row's why no longer claims a boot spelling routes to the driver. - one changeset with the narrowing kit. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016GiHYRmLSNWTfbX9gVQkpz
📓 Docs Drift CheckThis PR changes 3 package(s): 18 hand-written doc(s) name something this change touched — list omitted above 15 rows. Re-derive on the tree named below: ⛔ 7 release-owned page(s) also affected — read-only, see AGENTS.md Documentation Guardrails. What this run could not see
Coarse fallback — 148 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 5bf5a5550351bc49be3c944f5220f6cc1e116bb4 && git checkout 5bf5a5550351bc49be3c944f5220f6cc1e116bb4
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin eb9ef791bdc0034559924924bfffd3f762b531d6 b0b835ba75c9bb42ba7299874859065c9f3ef68f && git checkout -B drift-repro eb9ef791bdc0034559924924bfffd3f762b531d6 && git merge --no-ff b0b835ba75c9bb42ba7299874859065c9f3ef68f
node scripts/docs-audit/affected-docs.mjs --json eb9ef791bdc0034559924924bfffd3f762b531d6
|
Contract reviewServed-tier: Read: card #21492 (body and every comment, triage's first grade ① Derived judgmentsGoverning text: triage Spec (
Runtime (
CLI — right.
Docs, QA, ledger — right, with one nit.
Not in the diff, as ruled: ② Semver level
Clause-②: yes (narrowing) — right. The spec's published selection face drops three spellings and both hosts refuse boot selections they accepted; the PR body's line-initial ③ Boundary flagsDev flags (report
Observations, not blocking, none filed (carrier none):
Governance: not a governed-surface PR (no Gates on this head (latest run per name, read 2026-10-03T15:34Z after the last two concluded): every one of the seven required contexts is Implemented-by: VERDICT: PASS Generated by Claude Code |
Fixes #21492
Fixes #21572
Clause-②: yes (narrowing)
What this lands
One landing, as triage ruled (
5969348039, (ii)): #21572's spec row and #21492's runtime and CLI halves. The in-memory (mingo) engine is retired as a boot store, at its declaration, on both hosts. It refuses every tenant-scoped read by design, so a boot on it signed the seeded admin in and then answered503to every data read. Every boot door now refuses it with one sentence that names the replacement:os dev --freshfor a throwaway database, or the URL:memory:for SQLite's own in-memory database.packages/spec/src/data/driver/config-registry.zod.ts, the row fromd480ef0d70plus its stale doc comments):memory,mingoandin-memorymove from the selection face tocontractOnlyAliases, besideinmemory.DATABASE_DRIVER_SELECTION_ALIASES,DATABASE_DRIVER_SELECTION_IDS, the--database-driverallowlist and--helpdrop them by derivation.resolveDriverIdis unchanged, so a storeddatasource.driver: memorystill parses. No artifact moves (check:generated: all 15 up to date).resolveProjectDatabaseUrl: thememory-driverrung becomes a refusal that stands ahead of every rung.ProjectDatabaseUrlSourceloses'memory-driver'.resolveStandaloneDatabase: the URL detection recognisesmemory://andmingo://, andrefuseRetiredMemoryEnginerefuses them. It names the source: the typed URL,OS_DATABASE_URL, or the project's declared default datasource.unsupportedDriverMessagegives a spelling of the engine the retirement sentence, not the typo list.StandaloneDatabaseDriverSchemanow enumerates the selection face. The dispatch loses itsmemoryarm, andResolvedStandaloneDatabase.drivercan no longer name it.retiredMemoryEngineMessage, with the predicatenamesRetiredMemoryEngine. Both are exported for the CLI.inferDriverTypeFromUrlrefusesmemory://andmingo://withUnsupportedDriverError(recognized: false).resolveStorageDefinitionrefuses the spellings with the same sentence. Thememorydefinition arm is gone.--databasehelp ofdevandstartoffers:memory:instead ofmemory://.storage-driver.tscli:OS_DATABASE_DRIVER=memoryis advertised butserve.tshas no dispatch branch (falls through to SQLite) #3276 note and its module header are rewritten: the header now says which boots reach that file (legacy only). The parity pin's header, thedatabase-driver-flag.tsdoc and serve's comments are rewritten too.deployment/cli.mdx,deployment/environment-variables.mdx,data-modeling/drivers.mdx,plugins/index.mdx.docs/qa/platform-checklist/areas/cli.json, revisions bumped with history):cli.dev-boot-contract: the memory tier becomes a REFUSED variant, with a negative and the:memory:variant added.cli.migrate-duplicates-inventory: theno_sql_seamnegative cites the seam-double pin.5967974683:cli.build-own-contract's six live strings namethis.exit(2). Its two dated history entries keep their wording, because they record what was true when written.scripts/driver-memory-census.ledger.json's CLI rowwhyno longer claims that a boot spelling routes to the driver.fix(...)!, BREAKING,minorfor the three packages, and the ADR-0087 markernot-required (no-migration-prescription).The
driver-memorypackage is unchanged. A declared non-defaultdriver: 'memory'datasource and a directly constructedInMemoryDriverstill build: per the ruling, neither is a boot spelling.A1: reach, measured on both trees
Before, on
origin/main901e7cf13awithexamples/app-crm(closure build exit 0, 60/60 tasks):os dev --fresh --database-driver memoryGET /api/v1/data/crm_lead503SERVICE_UNAVAILABLE; the banner showsDatabase: file:/tmp/objectstack-dev-…/data/objectstack.dbbesideDriver: _InMemoryDriver → (in-memory)(the banner finding)os migrate plan --database-url memory://qadatasource 'default': connected (driver=memory …)os dev --fresh(control)SqlDriver(better-sqlite3)After, on this branch (
133871a251; the refusal code has not changed since):os dev --fresh --database-driver memoryExpected --database-driver=memory to be one of: sqlite, sqlite-wasm, postgres, mysql, mongodb, turso)os start --database-driver memoryOS_DATABASE_DRIVER=memory os dev --fresh(andmingo)Database:row, naming--freshand:memory:OS_DATABASE_DRIVER=in-memory os startos dev --fresh --database memory://xDatabase: memory://x; the serve child refuses, exit 1os migrate plan --database-url memory://qa/mingo://qa[StandaloneStack] The database URL "…" selects the in-memory (mingo) engine …os migrate duplicates --database-url memory://qa{"error":"boot_failed", …}with the sentenceOS_MODE=legacy OS_DATABASE_DRIVER=memory os serve --devOS_MODE=legacy OS_DATABASE_URL=mingo://x os serve --devOS_ARTIFACT_PATH=… OS_DATABASE_URL=memory:// os serve --dev(artifact path, empty cwd)os dev --fresh(control)SqlDriver(better-sqlite3)os dev --database :memory:(the replacement)Database: :memory:,SqlDriver(better-sqlite3) → :memory:A2: which doors reach which resolver (symbol walk)
resolveStandaloneDatabase, which callsresolveProjectDatabaseUrl), reached by:os serveover a config (createStandaloneStack) and over an artifact (createDefaultHostConfig, thencreateStandaloneStack); these are the serve children ofos devandos start;bootSchemaStackuser:os migrateapply,plan,meta,duplicates,account-issuer,audit-metadata-bodies,files-to-references,multi-value-columns,recorded-by,resume,summary-nullsandvalue-shapes, plusos meta resync,os secret orphans/rewrapandos storage orphans;probeMigrationTarget, the pre-boot probe of seven migrate subcommands;resolveProjectDatabaseUrl), reached by theos devandos startparents (resolveDevDatabase,resolveStartDatabase) and byos db clean.resolveDriverTypewithresolveStorageDefinition), reached byos serve's legacy path only:OS_MODE=off|none|legacy,bootMode: 'off', or a host config (shouldBootWithLibrary).A3: refusal shape and code
The refusals reuse each host's existing shape for an unrecognised driver or scheme: the runtime's plain
Error, prefixed[StandaloneStack]inside the standalone stack, and the CLI'sUnsupportedDriverError. No ledgered error code is involved, and the error-code ledger is not edited. The CLI flag door is oclif's own allowlist refusal, derived from the spec (see Acceptance notes).A4: parity pin
driver-vocabulary-parity.test.tsis the pin, with no exemption:DRIVER_ID_ALIASES.memory/mingo/in-memory, in dev and in prod, and both name--freshand:memory:.memory://,memory://named,mingo://andMINGO://upperwith no driver named.:memory:assqlite.mingo://cross-host divergence (the CLI accepted it, the runtime called it an unknown scheme) is closed: both hosts now recognise and refuse it.A5: the census ledger row
scripts/driver-memory-census.ledger.json, gated byscripts/check-driver-memory-census.mjs. The file is underscripts/: it is notpackages/specand not a governed surface. The CLI manifest row'swhyis rewritten, its axis is unchanged, andcheck:driver-memory-censusis green.A6: reverse verification
Both legs were run through
scripts/ablation-replace.mjson the committed tree (b0b835ba75), in WRAP mode, with a trap that restores fromHEADby absolute path.OS_ABLATION_RUNTIME_*env marker: the rung refusal,refuseRetiredMemoryEngine, and theunsupportedDriverMessagebranch. Each anchor went 1 to 0, and each blob changed.ablation-dist-preflightfound all three markers indist/(exit 0 each).dev-default-db2 red; the parity pin 7 red, each failing on its runtime-half lines (:231,:254).storage-driver.test.ts(the CLI host): green.HEAD,git diff HEADempty. Runtime rebuilt;preflight --absentexit 0 for all three markers.storage-driver.ts, the inference refusal and the spelling refusal; the anchors went 1 to 0. The tests import that file from source, so no build was involved.storage-driver.test.ts: 9 red. The parity pin: 7 red, each failing on its CLI-half lines (:225,:248).dev-default-db(runtime-backed).HEAD, 0 markers left,git diff HEADempty.Tests and gates (at
b0b835ba75)@objectstack/runtime(all projects): 319 files, 5210 passed and 19 skipped.@objectstack/cli--project unit: 254 files, 3742 passed.@objectstack/spec: 657 files, 18834 passed and 1 todo.os migrate/bootSchemaStackor spawnservewith a store flag or URL: 19 files, 210 passed and 1 skipped.duplicates.null-seam.test.tsnow boots nothing, so the tier predicate files it underunit.pnpm lintexits 0.@objectstack/spec check:generatedexits 0.dispatch-gates --commands(no paths) derived 121 for the 31 changed paths, and all 121 exit 0.--ranreports 121 run and 0 NOT-MEASURED. Three of them (check:skill-examples,check:dual-build-cjs-loads,check:i18n-coverage) first exited 3 for a missing build. They were re-run after a fullturbo run build --filter=!@objectstack/docs(exit 0) and exit 0.Acceptance notes
--database-driver memoryis refused by oclif's derived allowlist, in oclif's wording. It lists the legal kinds,sqliteamong them, but does not name--freshor:memory:. Making it do so would mean dropping the derivedoptions:or special-casing a value at the consumer. Both are forbidden bydatabase-driver-flag.tsand by the ruling. Every other door names the replacement.os dev --database memory://xprints the parent'sDatabase: memory://xrow, and the serve child then refuses, namingOS_DATABASE_URL(the channel it received the URL on). This is the same shape every unsupported scheme already has. The driver spelling is refused before the banner. The banner finding (afile:row beside an in-memory child) cannot occur any more.@objectstack/driver-memorydependency now serves no CLI-owned path. The ledger row says so. It is kept, because removing a published dependency is a packaging decision the ruling did not take. Carrier: none.duplicates.ts's header still quotes the originalmemory://qameasurement. That is a dated record of the defect, not an instruction.Generated by Claude Code