Repository navigation
fix(driver-memory)!: retire the legacy default export that CJS require() could not reach - #27323
Conversation
…e() could not reach
The package entry's default was a legacy { id, version, onEnable } object,
not a kernel plugin, and the CJS build put it on require(...).default while
the declarations said export default (attw FalseExportDefault). It leaves the
entry; every named export stays. ADR-0087 runtime-export-retired.
Claude-Session: https://claude.ai/code/session_017xRBcVyH9FzSkzAGmz8LNE
Co-authored-by: Claude <noreply@anthropic.com>
📓 Docs Drift Check1 anchor(s) derived from 1 changed package(s); no hand-written page names any of them. What this run could not see
Coarse fallback — 11 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 8d0d2e969c2da6e7a1fd31201eff724164d8639d && git checkout 8d0d2e969c2da6e7a1fd31201eff724164d8639d
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 19f49ef35418b5f5b11b5fd04337268335121fbd 161653aed2ee5d28e2db9f09d5ebbcc64a7ffcd5 && git checkout -B drift-repro 19f49ef35418b5f5b11b5fd04337268335121fbd && git merge --no-ff 161653aed2ee5d28e2db9f09d5ebbcc64a7ffcd5
node scripts/docs-audit/affected-docs.mjs --json 19f49ef35418b5f5b11b5fd04337268335121fbd |
|
domain:devx#1 · sunhaolin · session_017xRBcVyH9FzSkzAGmz8LNE Contract reviewServed-tier: Face: narrowing ( Check-runs on the head at review time: 18 success, 14 skipped, 13 in progress, 0 failure. Green and relevant: ① Derived judgmentsThe published surface is the root entry alone:
② Semver level
No disagreement with the declared level or lines. ③ Boundary flagsThe open question, verbatim from the report: "After this lands, a stack config that writes plugins: ['@objectstack/driver-memory'] silently registers nothing: materializeStackPlugin (packages/core/src/stack-plugins.ts:65) wraps the default-less module namespace into an AppPlugin that takes its no-id, no-payload branch. … Should the string-entry door refuse that loudly?" Answer: yes, the door should refuse loudly, and that refusal is a core change outside this card. Option A, with one tightening: the follow-up card is filed now, on the dev's seam reading, not conditionally after a later
Escalation flag for the seat, not a hold: whether the string spelling No other boundary crossed: no package added or removed, no ④ Design judgment
Prose faces, read for ② only: the README drops the Findings: 0 must-fix, 1 should-fix (test-header note), plus the ③ follow-up card against Implemented-by: VERDICT: PASS |
|
domain:devx#1 · sunhaolin · session_017xRBcVyH9FzSkzAGmz8LNE 席位核对 · ACCEPT · head
|
Fixes #26206
Clause-②: no (narrowing)
Metadata-protocol: none
Skills-docs: none — no
skills/**file and nocontent/docs/**page names the retireddefaultexport or loads the package as a string plugin; the docs teachInMemoryDriverby name, which stays维护者速读
@objectstack/driver-memory的包入口不再提供default导出(一个旧式的{ id, version, onEnable }对象)。InMemoryDriver等所有具名导出不变。这是本卡最后一项,前两项已由 fix(metadata-core,service-cluster,create-objectstack): ESM-only subpaths declare their types under import #26321、docs(cli): say the three code subpaths are ESM #26352 落地。require()时拿不到它,类型声明却说有(attw 报FalseExportDefault)。退役后 attw 对该包为 0 问题。plugins。外部若在配置里写了plugins: ['@objectstack/driver-memory'],原来会注册一个内存驱动,现在会静默不注册(changeset 写明改用new DriverPlugin(new InMemoryDriver(), 'memory'))。cloud / hotcrm 未能测到。回滚 = revert 本 PR。packages/drivers/driver-memory/src/index.ts(删掉的默认导出);.changeset/26206-driver-memory-default.md(BREAKING 说明、ADR-0087 处置与 FROM → TO);packages/drivers/driver-memory/src/default-export-retired.pin.test.ts。node scripts/check-adr-0087-registration.mjs --base origin/main,预期 exit 0 且打印verified: @objectstack/driver-memory#default。What changes
packages/drivers/driver-memory/src/index.ts: theexport default { id, version, onEnable }object leaves the published entry. Every named export stays. A comment at the old site says why the entry has no default and which named door to use.require('@objectstack/driver-memory')itself returns the default object. The entry also has 22 named exports, so that needs anexport =shape with the named exports merged onto the object. That changes what every CommonJS named import reads today, and it keeps an object that is not a kernelPlugin.require()calls, 0.defaultreads after a dynamic import, and 0 stringpluginsentries naming the package (evidence surface below). Control: 14 files (code, docs and skills) import named exports with a staticfrom, and 3 code files destructureInMemoryDriverfrom a dynamicimport().packages/drivers/driver-memory/README.md: thedefaultrow leaves the Key Exports table, and one line says the package has no default export..changeset/26206-driver-memory-default.md:patch(Metadata-protocolnone), BREAKING banner, ADR-0087not-required (runtime-export-retired @objectstack/driver-memory#default), and one FROM → TO line. No staged window.packages/drivers/driver-memory/src/default-export-retired.pin.test.ts(2 cases): the entry has nodefault, and the named exports stay andInMemoryDriverstill constructs.What changes for a string
pluginsentry (PM assumption 3)packages/cli/src/commands/serve.ts:2765(mod.default || mod) loads the project's own config file, not a plugin. The string-plugin door ismaterializeStackPlugininpackages/core/src/stack-plugins.ts:65: it loads the module and takesmod.default || mod, and an object with noinitis wrapped inAppPlugin, which runs a bundle'sonEnablewith adrivers.registerthat callsql.registerDriver. Measured at that seam (real coredist, real driver-memorydist, a recordingwrapBundle):wrapBundlereceivedid, version, onEnable, and callingonEnablewith a driver registry registeredInMemoryDriver(com.objectstack.driver.memory).wrapBundlereceives the module namespace (InMemoryDriver, …, noid, noonEnable).AppPluginthen takes its no-id, no-payload branch (packages/runtime/src/app-plugin.ts) and becomes an empty no-op plugin, so no driver is registered and nothing says so.So a config that writes
plugins: ['@objectstack/driver-memory']changes behaviour. No producer of that spelling was found (search below). The changeset names the replacement for that case.Tests
attw 0.18.5 on an npm-pack staging of driver-memory: before and after
Before (base
65b492081, attw exit 1):After (
161653aed, attw exit 0):The packed
dist/index.d.tshas 0export defaultlines after the change.driver-memory build, typecheck and tests at 161653a
pnpm --filter @objectstack/driver-memory build && … typecheck && … testunder the verify lock:VERDICT command-exit 0;Test Files 73 passed (73),Tests 1760 passed (1760).tsc --noEmit --listFilescounts the new pin test once (it is compiled by the typecheck program).Ablation (one-off, no permanent file)
The fix was committed first.
node scripts/ablation-replace.mjsreplaced the comment line at the old site withexport default { id: 'ablated' };(anchor 1 → 0, bloba1f49a03fbd9→f5bf6cfac4ce) and ran the pin test:× the published entry has no default export,AssertionError: expected true to be false,Tests 1 failed | 1 passed (2). Restored: blob == HEAD (a1f49a03fbd9),git diff HEADempty. The test imports./index.js, so it readssrc, and no build was needed for this leg.A first attempt used a replacement that contained its own anchor. The tool refused it before running anything ("the anchor count moved 1 -> 1"), so that attempt measured nothing.
Full dogfood battery at 161653a (the title carries a bang)
After
pnpm turbo run build --filter='./packages/**' --concurrency=2(75/75 tasks, 0 cached,VERDICT command-exit 0),pnpm --filter @objectstack/dogfood testunder the verify lock, no shard, no path:VERDICT command-exit 0,Test Files 348 passed | 3 skipped (351),Tests 2806 passed | 20 skipped (2826). No failures.Acceptance notes
objectstack-ai/objectstackat65b492081):git grepover the whole tree (examples/**,packages/create-objectstack/**templates,content/docs/**,skills/**,ui/**, every package's tests andscripts/**) forimport X from/import X, { … } from/import * as X fromof the package (0),require('@objectstack/driver-memory')(0), a dynamicimport()whose result is read as.defaultor destructured asdefault(0; the 3 code hits all destructureInMemoryDriver, the other 2 hits are comments), aplugins:line naming the package (0), and the default's idcom.objectstack.driver.memory(hits are the driver class's ownname, tests and CLI banner text, none of which reads the default object).content/docs/plugins/index.mdxandcontent/docs/plugins/packages.mdxteachInMemoryDriverby name.objectstack-ai/cloudandobjectstack-ai/hotcrm(this session's GitHub reads are bound to this repository; org code search answered 403), and npm dependants.driver-sql,driver-mongodb,driver-sqlite-wasm,driver-turso) export the same legacy{ id, version, onEnable }default. attw 0.18.5 on npm-pack stagings of all four at161653aedreports no problems (exit 0). So they are not part of this card's acceptance, and this PR does not touch them. Why attw flags driver-memory's build and not theirs (the CJS output has the same shape) was not established.pluginsentry naming any module without a default export and withoutinitgets the module namespace wrapped into an emptyAppPlugin. That was read at the seam, not measured throughos serve, so it is recorded here and not filed.check-adr-0087-registration --base origin/mainexit 0,verified: @objectstack/driver-memory#default (export, packages/drivers/driver-memory/src/index.ts). The blocker fixcdb949a288is an ancestor of the base (merge-base --is-ancestorexit 0).Verification
Local, at
161653aed, derived withnode scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstackover this diff (58 commands). Every command ran, and each exit code was captured before any pipe.check-plugin-teardown-shape --self-test(its pinned fixture commit was outside the shallow clone) andcheck:dual-build-cjs-loads/check:lean-entry-closure(they read built output). They were re-run aftergit fetch --depth=1of the fixture commit and the full packages build, and all 3 exited 0:112 published require entry point(s) across 69 package(s) load,Admitted set held exactly (15 packages),48 cases pass.dispatch-gates --ran:58 derived, 58 run, 0 NOT-MEASURED, 0 UNRUN(exit 0).check-platform-checklist --changed-from origin/mainexit 0 (0 anchored files),check:published-readme-exportsexit 0,check:published-readme-linksexit 0,check-nul-bytesexit 0.test:repoand repo-wide lint were not run locally. They belong to CI (Test Core,Lint & Repo Gates) on this PR.Generated by Claude Code