Repository navigation
fix(service-datasource): a missing optional driver package (turso, mongodb, sqlite-wasm) is refused with the factory's install alone, not the unbuilt-workspace build advice - #24971
Conversation
…efusal on the factory's install, not the build advice A bare @objectstack/driver-turso / -mongodb / -sqlite-wasm specifier is a missing install the project makes itself; the refusal now ends on one sentence deferring to the install the factory text already names. A path into one of those packages stays on the unbuilt-workspace remedy. Claude-Session: https://claude.ai/code/session_011TdZ8GjixNZFLz1xJD9zzK Co-authored-by: Claude <noreply@anthropic.com>
…tory classifier pins read a path for the unbuilt case Claude-Session: https://claude.ai/code/session_011TdZ8GjixNZFLz1xJD9zzK Co-authored-by: Claude <noreply@anthropic.com>
…ckage remedy Claude-Session: https://claude.ai/code/session_011TdZ8GjixNZFLz1xJD9zzK Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011TdZ8GjixNZFLz1xJD9zzK Co-authored-by: Claude <noreply@anthropic.com>
📓 Docs Drift Check6 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 — 2 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 62f0b35a2a0f5ef2342cb38a1f1bbe164d1237b6 && git checkout 62f0b35a2a0f5ef2342cb38a1f1bbe164d1237b6
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 6440cf16334e1c8106dfdb31d87b6ca728d176c2 e759c6c8e976be2c01593ab191fe7fa9bca6ab21 && git checkout -B drift-repro 6440cf16334e1c8106dfdb31d87b6ca728d176c2 && git merge --no-ff e759c6c8e976be2c01593ab191fe7fa9bca6ab21
node scripts/docs-audit/affected-docs.mjs --json 6440cf16334e1c8106dfdb31d87b6ca728d176c2 |
Claude-Session: https://claude.ai/code/session_011TdZ8GjixNZFLz1xJD9zzK Co-authored-by: Claude <noreply@anthropic.com>
… the three optional driver packages A required @objectstack/ driver package that is not installed still ends on the build advice; the optional driver-turso, driver-mongodb and driver-sqlite-wasm now end on their own install. Claude-Session: https://claude.ai/code/session_011TdZ8GjixNZFLz1xJD9zzK Co-authored-by: Claude <noreply@anthropic.com>
席位核对 · ACCEPT ·
|
Fixes #24937
Clause-②: no
What was wrong
A
turso,mongodborsqlite-wasmdatasource whose optional driver package is not installed is refused at boot. The factory's own text already says so and names the install (npm install @objectstack/driver-turso, with thepnpm addandyarn addspellings beside it). The refusal then ended onUNBUILT_WORKSPACE_REMEDYanyway: "… That is a build precondition … Runpnpm install && pnpm build, then start again." That is two fixes that contradict each other, and the second does nothing for a project, which adds these packages itself.connectFailureRemedy()chose the unbuilt remedy for every module-not-found except the three database clients PR #24933 split off (pg,mysql2,better-sqlite3). A bare@objectstack/driver-*specifier still classified as unbuilt, and four factory classifier pins asserted that.What changed
Seat ruling B on the card. The code change is in
packages/services/service-datasource/src/connect-failure-remedy.ts, and it is a message branch only.OPTIONAL_DRIVER_PACKAGES, built from the factory's own constants (TURSO_DRIVER_PACKAGE,MONGODB_DRIVER_PACKAGE,SQLITE_WASM_DRIVER_PACKAGE). A pin holds it equal to the optional peerspackage.jsondeclares (peerDependenciesMeta.*.optional). Measured set: exactly those three.missingOptionalDriverPackage(cause)reads the same firstCannot find module|package 'X'specifier PR fix(service-datasource): a missing database client (pg, mysql2, better-sqlite3) is refused with its install, not the unbuilt-workspace build advice #24933 introduced. It answers X only when X is one of those three, as a bare name.connectFailureRemedy()then ends onmissingOptionalDriverPackageRemedy(X). That is ONE sentence deferring to the install the factory text already names: "The fix is the install ofXnamed above, then start again: it is an OPTIONAL driver package the project adds itself, so a build cannot produce it and no boot-time override can stand in for it." It names no command, no build, no environment variable and no configuration key.isUnbuiltWorkspaceFailure()answers false for that case.…/driver-turso/dist/index.mjs) keepsUNBUILT_WORKSPACE_REMEDY, and so does a subpath of one.@objectstack/driver-sqland any other@objectstack/…name keep it too.GENERIC_CONNECT_FAILURE_REMEDY, byte for byte.Unchanged, per the hard stops:
default-datasource-driver-factory.tsis not in the diff.OS_ALLOW_DRIVER_CONNECT_FAILUREpath.sqlite-driver-fallback.ts,packages/types/**,packages/drivers/**andpackages/spec/**are not touched.Premise re-check (the ruling's P), measured before any edit
P: in this monorepo, once
pnpm installhas run, a missing or unbuilt optional driver surfaces as a PATH, not as a bareCannot find packagename.Setup: a fresh worktree at
8cfe1f94cb,pnpm install --frozen-lockfile, no build. All three packages are linked intoservice-datasource/node_modules/@objectstack/.packages/services/service-datasource. For each package, ESM and CJS both answer a path:ERR_MODULE_NOT_FOUND | Cannot find module '…/service-datasource/node_modules/@objectstack/driver-turso/dist/index.mjs' imported from …MODULE_NOT_FOUND | Cannot find module '…/driver-turso/dist/index.js'driver-mongodbanddriver-sqlite-wasmanswer the same shape.my_app_notebooted per driver through the real factory and the realDatasourceConnectionService(builtdist/). Every arm's first unresolved specifier is the…/driver-X/dist/index.mjsPATH.P holds, so B ships. A contributor with an unbuilt checkout is still told to build. That is unchanged by this PR, and the pins for it are now path-shaped.
Measured on the card's path, before and after
The published
@objectstack/service-datasource@18.0.0was installed alone in an empty directory, with no driver packages (npm install --ignore-scripts). A declared datasource bound to one object was booted per optional driver through the published factory andDatasourceConnectionService, under bothdist/index.js(ESM) anddist/index.cjs(CJS).@objectstack/driver-turso(-mongodb,-sqlite-wasm);npm installonce AND ends on "… Runpnpm install && pnpm build, then start again."pnpm packofservice-datasource, marker grep: positive control 1 hit, the 18.0.0 copy 0 hits):@objectstack/driver-Xnamed above, then start again: …";npm installappears exactly once in the whole refusal;pnpm installandpnpm buildare absent.os devscaffold path itself (create-objectstack@18.0.0, a turso datasource). Reason: the CLI reaches this refusal through the same factory andDatasourceConnectionServicemeasured above. The card measured the scaffold's before-state, and a scaffold after-state needs this unpublished build overridden into a full CLI install.Tests (head
87b717e5a0)pnpm --filter @objectstack/service-datasource typecheck:tsc --noEmit, exit 0.--listFilesincludes both edited test files.pnpm --filter @objectstack/service-datasource test:Test Files 49 passed (49),Tests 899 passed (899).datasource-connection-service.test.ts):Cannot find package 'X' imported from …withERR_MODULE_NOT_FOUND, CJSCannot find module 'X'plusRequire stackwithMODULE_NOT_FOUND} goes through the factory's real message builders (the turso one asMissingDriverPackageError). Each ends on the deferring sentence. The whole refusal holds exactly onenpm install, nopnpm build, nopnpm install, no unbuilt remedy and no generic advice.OS_*variable or--database.@objectstack/driver-sqlis not on the list, a code-only error names nothing.ECONNREFUSED/28P01generic pins are unchanged and green.default-datasource-driver-factory.test.ts). The card says three; there are FOUR sites assertingisUnbuiltWorkspaceFailure(...)true on a bare-package cause: the turso, sqlite-wasm and mongodb "keeps the import error verbatim" cases, and the three-arm parity case.unbuiltCause(pkg), the measured shape).@vitest/mockercreateHelpfulError, measured in the installed 4.1.11). A staged absence therefore cannot carry Node's text to the classifier. The factory has no import seam, and its file is off this PR's surface. The before/after run above is the real-path evidence instead.Ablation (one leg per changed behaviour; fix committed first;
node scripts/ablation-replace.mjs, WRAP mode)Each leg ran the three suites
datasource-connection-service,default-datasource-driver-factoryandmissing-driver-client-boot-refusal. The subjects resolve through relativesrcimports, so nodist/leg applies.connectFailureRemedybranch (if (driverPackage !== undefined) return missingOptionalDriverPackageRemedy(driverPackage);).e6403dd54e18→bf36838df528.Tests 6 failed | 150 passed, exactly the six ESM/CJS deferring-remedy pins.git checkout HEAD --: blobe6403dd54e18== HEAD,git diff HEADempty,git statusclean.isUnbuiltWorkspaceFailureexclusion (&& missingOptionalDriverPackage(cause) === undefined).e6403dd54e18→ebf06e9d96f4.Tests 5 failed | 151 passed, exactly the five classifier pins. The four factory sites plus the unit failed; the remedy pins stayed green.git diff HEADempty.Gates (local subset, head
87b717e5a0)node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack, 66 commands, 4 changed paths vs merge base8cfe1f94c.pnpm check:dual-build-cjs-loads. It exited 3 withPREREQUISITE NOT MET: it reads every package'sdist/, and this worktree builds only theservice-datasourceclosure. CI'sLint & Repo Gatesruns it.--ranreconciliation:✓ dispatch-gates --ran: 66 derived famil(ies) accounted for — 65 run, 1 NOT-MEASURED (1 DERIVED from a recorded exit 3), exit 0.Test Core,Build Core, the type-check lanes) are CI's.Acceptance notes
.changeset/24909-missing-driver-client-remedy.mdis still unreleased. It reads "an@objectstack/…driver package that is not installed, still ends onpnpm install && pnpm build". That stops being true for the three optional driver packages.@objectstack/…driver package that is not installed".default-datasource-driver-factory.ts, themissingTursoDriverMessagedoc says the classifier "can only recognise an unbuilt/uninstalled workspace" from the interpolated text. With this change an uninstalled optional package is read as an install, not as unbuilt. The file is off-surface by the hard stop, and nothing else in it is made false. Carrier: none.npm install @objectstack/driver-X", and the refusal then correctly ends on the build advice. The boot-leg measurement above showsnpm installandpnpm buildboth present. That is the factory message's wording, which is out of scope here by the hard stop, and ruling B accepted the workspace reading. It was measured at the service seam only, with no public door. Carrier: none.Round 2: the client-remedy changeset's "Unchanged" bullet (seat ruling A on open question 1)
.changeset/24909-missing-driver-client-remedy.mdis still unreleased. Its "Unchanged" bullet said "an@objectstack/…driver package that is not installed, still ends onpnpm install && pnpm build", which this PR makes false for the three optional driver packages. That one bullet now reads:1 insertion(+), 1 deletion(-)). No other line of that file changed, and no other file changed in this round.dist/is still the unbuilt remedy, and so is a bare@objectstack/…name offOPTIONAL_DRIVER_PACKAGES(e.g.@objectstack/driver-sql). A bare name on that list ends onmissingOptionalDriverPackageRemedy.origin/main693352e4c2was merged first. It brings PR fix(service-datasource): in development, a SQLite file that cannot be opened or created fails its connect instead of stepping down to an in-memory engine #24955 onsqlite-driver-fallback.ts, disjoint from this diff.e759c6c8e9:pnpm --filter @objectstack/service-datasource typecheck: exit 0.pnpm --filter @objectstack/service-datasource test:Test Files 50 passed (50),Tests 908 passed (908). That includes fix(service-datasource): in development, a SQLite file that cannot be opened or created fails its connect instead of stepping down to an in-memory engine #24955's new file.node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack. That gives 5 paths vs merge base693352e4cand 66 commands, the same set as round 1 (the new path adds no family). All 66 were re-run at this head under the lock,node scripts/check-empty-changeset.mjs --base origin/mainamong them. Results: 64 exit 0; 1 NOT MEASURED,pnpm check:dual-build-cjs-loads(exit 3,PREREQUISITE NOT MET, it reads every package'sdist/); and 1 red BY DESIGN,node scripts/check-empty-changeset.mjs --base origin/main(exit 1).--ranreconciliation:✓ dispatch-gates --ran: 66 derived famil(ies) accounted for — 65 run, 1 NOT-MEASURED (1 DERIVED from a recorded exit 3), exit 0.Check Changesetstays red, and that is the gate's DELIBERATE CORRECTION classcheck-empty-changesetrefuses any PR that changes a changeset it did not add. Here that is.changeset/24909-missing-driver-client-remedy.md,Magainst merge base693352e4c, beside this PR's ownA.changeset/24937-optional-driver-package-remedy.md. The gate names two classes with opposite remedies. This is the second one, not a filename collision: this PR's own code change made that PENDING release note false, and this round rewrites only the sentence it falsified. Per the gate's own remedy text, whichpr-automation.yml's route 0 repeats for the same class:skip-changesetis NOT applied. Ruled on [finding] theskip-changesetlabel suppresses the DELIBERATE-CORRECTION refusal whose own text says 「no label and no diff shape makes that safe」 — declared contract against enforced behaviour #18375 (ruling D): never on a PR that edits an existing changeset.Check Changesetis not one of the five required contexts, so it blocks no merge.The note is
.changeset/24909-missing-driver-client-remedy.md. What changed under it: this PR routes a bare@objectstack/driver-turso/-mongodb/-sqlite-wasmmodule-not-found to the factory's install instead of the build advice. Only its "Unchanged" bullet's second clause is narrowed to match. The correction was ruled by thedomain:servicesseat 1 PM (ruling A on open question 1 of the os-dev report on #24937). The seat records that confirmation on this PR in writing.Generated by Claude Code