You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
package-registry is on the always-on slate but Serve.CAPABILITY_PROVIDERS does not key it — the always-on mount is silently inert (#17676 ruling A' runtime half) #19387
'package-registry' is an always-on platform capability that mounts nothing, and it fails silently. Ruling A′ on #17676 (decision batch #125, maintainer 「同意」 2026-09-13) landed its spec half; the runtime half — the entry that actually mounts the provider — is not landed, so the ruling's own consequence is false on today's tree.
The chain, measured on origin/main8271c814253fdd2629d3b608b73de14efb67f168
the no-provider branch warns only when declaredRequires.has(cap) && !PLATFORM_CAPABILITY_TOKENS.includes(cap). A force-appended token that is in the vocabulary fails ⛔ both conjuncts ⇒ bare continue — no warn, no error
⇒ on a stock boot of an app that does not itself declare requires: ['marketplace'] (examples/app-crm declares ['ui','automation']), POST /api/v1/packages reaches protocol.installPackage with no package service and registers the package in memory only. It does not survive a restart. That is #17676's defect, still live.
⭐ Worse than a missing mount: a reader of the spec sees package-registry on the always-on slate and reasonably concludes it is mounted everywhere. AGENTS.md principle 3 — Absence must be loud is exactly what this violates.
The shape question — and how much of it is already decided
Two shapes are available. ⚠️ They are not equal candidates, and the reason is textual rather than a preference:
what it does
cost
A — ADD
key package-registry at @objectstack/service-package too, leaving marketplace pointing there as well
Smallest diff, and hasPluginMatching already stops a double mount. ⛔ But it re-enacts the conflation the carve-out exists to end, and it contradicts ruling A′ item 1's own sentence.
B — MOVE
package-registry takes @objectstack/service-package; marketplace is repointed at the browse surface (MarketplaceProxyPlugin / MarketplaceInstallLocalPlugin in @objectstack/cloud-connection, off a resolved marketplace URL, ADR-0008)
⚠️ Changes what requires: ['marketplace'] means for apps shipping today. Needs a migration story, and probably an ADR-0087 disposition.
Ruling A′ item 1 already says what the two names mean, and it is quoted in the spec file itself: the persistence half "is a core capability named for what it is and mounted always … marketplace is left naming only the optional catalogue / browsing half." ⇒ A contradicts the landed ruling; only B makes item 2's sentence ("therefore always find the package service on a stock boot") true while leaving the two names meaning what the ruling says.
⚠️ What ruling A′ did not decide, and this card must: the migration for declarers. The spec's provider row is explicit that it declines to pre-empt this —
"the two rows agreeing on a package is what the carve-out INHERITED, not what it decided: repointing marketplace at the browse surface moves the runtime's own resolver with it and is #17676's engine-lane half, which this row deliberately does not pre-empt."
A real declarer to design against, ⛔ not a hypothetical:examples/app-showcase/objectstack.config.ts:107 declares 'marketplace', and its own comment at :103 says it declares it for "PackageServicePlugin (sys_packages store)" — i.e. for the persistence half. The same file separately wires the browse plugins through plugins[]. ⇒ under B that declaration becomes vestigial (the store arrives always-on) and the browse auto-mount is skipped by the identity guard — but an out-of-repo consumer that declared marketplace for the store has no such explicit wiring, and the taker must say what happens to it.
⭐ The pin that is waiting to be written
packages/cli/test/serve-capability-vocabulary.test.tsdeliberately declines to pin that Serve.CAPABILITY_PROVIDERS lacks package-registry, so the engine lane's own change would not be turned red for doing the ruled thing. ⇒ today nothing mechanical would notice if this half were forgotten again — the gap lives only in two prose comments, in that test and in the spec.
Whoever takes this should convert that prose into the pin it was waiting to be able to write. ⛔ Otherwise the next carve-out repeats this exact failure.
The absence direction is pinned, so a future slate entry with no mount entry goes red.
The declarer migration is stated in writing, with its ADR-0087 disposition answered rather than assumed.
File surface
packages/cli/src/commands/serve.ts (the mount table) and packages/cli/test/serve-capability-vocabulary.test.ts (the pin). ⚠️ Touching examples/app-showcase/objectstack.config.ts depends on the migration answer, ⛔ not assumed here.
Lane — ⛔ deliberately unlabelled
Left for triage. ⚠️ The two prose notes call this "the engine lane", meaning #17676's lane — but the files live in packages/cli, which the lane table routes elsewhere. ⇒ the routing is genuinely a triage call and ⛔ this filer is not making it and has written no domain:* label.
⚠️If the taking lane's PM reads the declarer-meaning change as a contract-shape proposal rather than execution, the four-axis decision route is the right escalation — ⛔ this filer is not foreclosing it, and is equally ⛔ not manufacturing a decision the maintainer already made in item 1.
Surfaced as the fork in the os-dev report on #17676 (PR #19385) and independently re-derived link-by-link by the domain:engine execution PM seat, round 7 — which also records there that the dispatch order's assumption that item 1 discharged item 2 was the seat's own error. Related: #17676 (the ruling) · #18053 (item 1's carrier) · PR #19385 (items 2/3).
What is wrong
'package-registry'is an always-on platform capability that mounts nothing, and it fails silently. Ruling A′ on #17676 (decision batch #125, maintainer 「同意」 2026-09-13) landed its spec half; the runtime half — the entry that actually mounts the provider — is not landed, so the ruling's own consequence is false on today's tree.The chain, measured on
origin/main8271c814253fdd2629d3b608b73de14efb67f168packages/spec/src/kernel/platform-capabilities.ts:312+ —PLATFORM_ALWAYS_ON_CAPABILITIESlists'package-registry':179—'package-registry': { package: '@objectstack/service-package', edition: 'open' }serveforce-appends every slate tokenpackages/cli/src/commands/serve.ts:2800-2802, theALWAYS_CAPSloopServe.CAPABILITY_PROVIDERS(serve.ts:1863+) keysautomation · analytics · audit · cache · storage · queue · job · messaging · triggers · realtime · mcp · **marketplace** · email · sms · sharing · pinyin-search · reports · approvals · settings · webhooks— ⛔ nopackage-registrydeclaredRequires.has(cap) && !PLATFORM_CAPABILITY_TOKENS.includes(cap). A force-appended token that is in the vocabulary fails ⛔ both conjuncts ⇒ barecontinue— no warn, no error⇒ on a stock boot of an app that does not itself declare
requires: ['marketplace'](examples/app-crmdeclares['ui','automation']),POST /api/v1/packagesreachesprotocol.installPackagewith nopackageservice and registers the package in memory only. It does not survive a restart. That is #17676's defect, still live.⭐ Worse than a missing mount: a reader of the spec sees
package-registryon the always-on slate and reasonably concludes it is mounted everywhere.AGENTS.mdprinciple 3 — Absence must be loud is exactly what this violates.The shape question — and how much of it is already decided
Two shapes are available.⚠️ They are not equal candidates, and the reason is textual rather than a preference:
package-registryat@objectstack/service-packagetoo, leavingmarketplacepointing there as wellhasPluginMatchingalready stops a double mount. ⛔ But it re-enacts the conflation the carve-out exists to end, and it contradicts ruling A′ item 1's own sentence.package-registrytakes@objectstack/service-package;marketplaceis repointed at the browse surface (MarketplaceProxyPlugin/MarketplaceInstallLocalPluginin@objectstack/cloud-connection, off a resolved marketplace URL, ADR-0008)requires: ['marketplace']means for apps shipping today. Needs a migration story, and probably an ADR-0087 disposition.Ruling A′ item 1 already says what the two names mean, and it is quoted in the spec file itself: the persistence half "is a core capability named for what it is and mounted always …
marketplaceis left naming only the optional catalogue / browsing half." ⇒ A contradicts the landed ruling; only B makes item 2's sentence ("therefore always find thepackageservice on a stock boot") true while leaving the two names meaning what the ruling says.A real declarer to design against, ⛔ not a hypothetical:
examples/app-showcase/objectstack.config.ts:107declares'marketplace', and its own comment at:103says it declares it for "PackageServicePlugin (sys_packagesstore)" — i.e. for the persistence half. The same file separately wires the browse plugins throughplugins[]. ⇒ under B that declaration becomes vestigial (the store arrives always-on) and the browse auto-mount is skipped by the identity guard — but an out-of-repo consumer that declaredmarketplacefor the store has no such explicit wiring, and the taker must say what happens to it.⭐ The pin that is waiting to be written
packages/cli/test/serve-capability-vocabulary.test.tsdeliberately declines to pin thatServe.CAPABILITY_PROVIDERSlackspackage-registry, so the engine lane's own change would not be turned red for doing the ruled thing. ⇒ today nothing mechanical would notice if this half were forgotten again — the gap lives only in two prose comments, in that test and in the spec.Whoever takes this should convert that prose into the pin it was waiting to be able to write. ⛔ Otherwise the next carve-out repeats this exact failure.
Acceptance
marketplacenorpackage-registry) mounts the package service, and an API-created package survives a restart — which is A writable package created viaPOST /api/v1/packagesis registered in memory only — it does not survive a restart, and leaves its published metadata orphaned #17676 ruling A′ item 5, whose three-probe acceptance ⛔ cannot be met by anything until this lands.File surface
packages/cli/src/commands/serve.ts(the mount table) andpackages/cli/test/serve-capability-vocabulary.test.ts(the pin).examples/app-showcase/objectstack.config.tsdepends on the migration answer, ⛔ not assumed here.Lane — ⛔ deliberately unlabelled
Left for triage.⚠️ The two prose notes call this "the engine lane", meaning #17676's lane — but the files live in
packages/cli, which the lane table routes elsewhere. ⇒ the routing is genuinely a triage call and ⛔ this filer is not making it and has written nodomain:*label.Dedupe words (⛔ the filer does not dedupe)
package-registry inert·CAPABILITY_PROVIDERS·ALWAYS_ON silent continue·marketplace carve-out·#17676 runtime halfProvenance
Surfaced as the fork in the
os-devreport on #17676 (PR #19385) and independently re-derived link-by-link by thedomain:engineexecution PM seat, round 7 — which also records there that the dispatch order's assumption that item 1 discharged item 2 was the seat's own error. Related: #17676 (the ruling) · #18053 (item 1's carrier) · PR #19385 (items 2/3).Generated by Claude Code