Uh oh!
There was an error while loading. Please reload this page.
feat(spec): storage becomes the canonical core-service slot; file-storage stays a deprecated v17 alias - #9820
Conversation
…rage stays a deprecated v17 alias (#9683) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016D9wdJR14KKCxz1WgdAzcw
…e enum (#9683) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016D9wdJR14KKCxz1WgdAzcw
…l storage slot name (#9683) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016D9wdJR14KKCxz1WgdAzcw
…TS2347 debt ledger (#9683) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016D9wdJR14KKCxz1WgdAzcw
📓 Docs Drift CheckThis PR changes 8 package(s): 12 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:
⛔ 3 release-owned page(s) also name something this change touched. These are read-only:
What this run could not see
Coarse fallback — 129 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 6d5e5993a23384c7b5b5d85209c8b8a5f40a1acb && git checkout 6d5e5993a23384c7b5b5d85209c8b8a5f40a1acb
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin e124e58f9525e278bba7583cd9a505ab5681d92c 395e5c4a92d4eed5f652dde1ffac96e256e85f74 && git checkout -B drift-repro e124e58f9525e278bba7583cd9a505ab5681d92c && git merge --no-ff 395e5c4a92d4eed5f652dde1ffac96e256e85f74
node scripts/docs-audit/affected-docs.mjs --json e124e58f9525e278bba7583cd9a505ab5681d92c
|
Uh oh!
There was an error while loading. Please reload this page.
Fixes#9683
Ruling implemented
Maintainer ruling, 2026-08-18, verbatim: 「9683 file-storage 可以叫 storage」 — recorded in issue comment 5334896426.
storagebecomes the canonicalCoreServiceNameslot; the resolution is a rename, superseding the card body's "not proposing a rename" framing and the #9630 dispatch-time no-rename note.file-storagewas the only member of the enum whose spelling diverged from its documented accessor, with no recorded reason anywhere in the tree.Falsifiable-premise measurement (verdict: NO structural conflict — premise valid)
The ruling required measuring whether the
/api/v1/storageroute namespace andObjectStackClient.storagestructurally conflict with a service slot namedstoragebefore renaming. Measured:registerService(name: string, ...)/getService(name)key a plainMapin the kernel (packages/core/src/kernel.ts); nothing derives a route path or accessor from a slot name./api/v1/storagefrom a hardcodedbasePathdefault; metadata-protocol'sSERVICE_CONFIGand the dispatcher's route ledger carry the path as literals.ObjectStackClient.storagereads thestorageROUTE key from the discoveryroutesmap (this.getRoute('storage')), which is produced by an explicitserviceToRouteKeytable — a namespace separate from service slots. After the rename that table mapsstorage → storage; the coincidence of names is an identity across two explicit records, not a collision.servicesis an open record (z.record(z.string(), ServiceInfoSchema)), so the key set is not closed against the new member.One additional consumer was found and handled (see the discovery mirror below): objectui's console endpoint catalog reads the
file-storagekey off the discovery document.What changed
packages/spec(minor):CoreServiceNamegainsstorageas the canonical member;file-storagestays an accepted member, JSDoc-marked as the deprecated v17 alias pointing atstorageand the ruling.CORE_SERVICE_PROVIDERandServiceRequirementDefcarry both keys.CoreServiceContractsgainsstorage: IStorageService; thefile-storageentry is annotated as the deprecated alias — deliberately the same pattern as the existinghttp.server/http-serverpair in the same file.contracts/storage-service.tsheader andapi/discovery.zod.tsfiles-capability JSDoc updated.Alias mechanism — registration-side, the smallest shim (
@objectstack/service-storage): the plugin registers the sameSwappableStorageServiceinstance under both names and declaresprovidesServices = ['storage', 'file-storage']. Pinned by an alias-equivalence test:getService('storage')andgetService('file-storage')return the SAME instance. This follows the repo's ownhttp.server/http-serverprecedent; no kernel/lookup changes, no consumer-side fallbacks.Internal resolvers move to the canonical name:
packages/runtime/src/http-dispatcher.ts(discovery resolution),packages/plugins/plugin-email/src/email-plugin.ts(attachment store),packages/cli/src/commands/migrate/files-to-references.ts.Discovery reports
storage— and mirrors the row verbatim underfile-storagefor v17. Both producers (dispatchergetDiscoveryInfo, metadata-protocolgetDiscovery) key the canonicalservices.storagerow and emit a byte-equal copy under the alias key. Reason: objectui's console endpoint catalog (useApiDiscovery.ts, shaped by objectui#4240) reads thefile-storageservices key; dropping the key would be a silent inside-a-major break of a shipped reader — the same class the ruling forbids forgetService. Pinned in both producers' tests (filled and empty slot alike). The mirror retires with the alias at the next major (#9819 tracks the full footprint; #9819 remains open).plugin-dev: the storage service toggle accepts both spellings (
services: { storage: false }or the pre-rename'file-storage': false); a test pins the alias-toggle compatibility.Docs:
kernel/runtime-services/storage-service.mdxnow declares Registry slotstoragewith the alias section (the "Accessor name vs registry slot" exception section is gone — accessor and slot are the same word again);kernel/runtime-services/index.mdx,kernel/contracts/storage-service.mdx,kernel/services-checklist.mdx,api/plugin-endpoints.mdx, READMEs updated;content/docs/references/pages regenerated viagen:docs(never hand-edited).scripts/check-runtime-services-index.mjsheader prose updated to record the ruling (its old prose declaredfile-storagecanonical and warned against exactly this rename; the gate's mechanics are unchanged and green — the storage page's declared slot is held to the real registrations, which now include both keys).Changeset: spec minor (enum member addition + deprecation annotation — deliberately not major; the alias keeps v17 compatibility), patch for service-storage, runtime, metadata-protocol, cli, plugin-email, plugin-dev. ADR-0087: not-required (a registry slot name is not authorable metadata; compatibility is carried by the enum + dual registration, retirement at the next major).
Remaining
'file-storage'references (whole-tree grep, each deliberate)CORE_SERVICE_PROVIDER/ServiceRequirementDefrows, contracts entry, dual registration, discovery mirror rows, dev-plugin toggle, and the tests pinning each.storageand the ruling (spec, docs, READMEs, gate-script history notes).docs/audits/2026-06-handwritten-docs-accuracy-followups.md, spec migration-registry entries (e.g.17.storage-service-list-retired), retired-bridge narration indispatcher-plugin.ts/http-dispatcher.test.tscomments, ADR-0076/0115 (governed surface).spec/integration,build-docs.ts, protocol/objectql docs) and thesys_emailattachment help text plus its generated translation bundles (prose about the capability; churning them would dirty three hand-translated locales for zero contract value).Verification (all at head
395e5c4, after merging origin/main)pnpm build --concurrency=2over the whole workspace (71 packages, the downstream closure of spec) green at head.packages/runtimeacceptedCoreServiceName.enum.storageand the alias, and a@ts-expect-erroron a bogus member was satisfied — proving consumers read the rebuilt declarations, not a stale dist.pnpm --filter @objectstack/spec check:generatedgreen aftergen:docsregen;check:runtime-services-index(incl. the newruntime-services/versioning.mdx's stability matrix omitsservices.sms— a fourth enumeration of the chapter that #9634's gate does not hold #9684 stability-matrix claim) and its--self-testgreen;check:service-providersgreen (14 slots).node scripts/pm/dispatch-gates.mjsre-derived on the actual diff; every named gate run and green at head, includingcheck:i18n,check:type-check-debt --re-measure(ratchet exactly at its measurements),check:engine-double-contract,check:where-matcher,check:adr-0087-registration,check:changeset-no-major. One transient red was diagnosed as a stale pre-merge CLI dist (the i18n extractor banner), fixed by rebuilding — no bundle changes were committed.Out of scope, filed unassigned
file-storageslot — move to the canonicalstoragekey (framework #9683) objectui#5286 — console endpoint catalog moves to the canonical key (kept working meanwhile by the discovery mirror).@ts-expect-error退役 pin 在packages/spec里是幽灵检查:tsconfig 把**/*.test.ts排除出唯一的tsc --noEmit#5286 remains open.file-storageCoreServiceName alias at the next major (standard retirement flow) — ledger of known alias readers #9819 — alias retirement at the next major, with the ledger of known alias readers (including the cloud repo'sservice-cloudartifact API, not verifiable from this repository). Retire the deprecatedfile-storageCoreServiceName alias at the next major (standard retirement flow) — ledger of known alias readers #9819 remains open.Generated by Claude Code