Repository navigation
fix(runtime): the package install and enable routes announce metadata:reloaded - #33448
Conversation
…reloaded POST /packages and PATCH /packages/:id/enable now announce `metadata:reloaded` with `changed: ['app/ID']` once the package is in service, the spelling the marketplace install-local door uses, so every subscriber (the renamedFrom holder carry, flows, hooks, actions, translations) re-syncs without a restart. Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016WV4cykhsWAtSL6Sr4VWFG
Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016WV4cykhsWAtSL6Sr4VWFG
Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016WV4cykhsWAtSL6Sr4VWFG
📓 Docs Drift CheckThis PR changes 1 package(s): 5 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:
⛔ 1 release-owned page(s) also name something this change touched. These are read-only:
What this run could not see
Coarse fallback — 30 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 8005fd564855b9f122afe896f8e90ca3cd9af4c9 && git checkout 8005fd564855b9f122afe896f8e90ca3cd9af4c9
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 7e61983e18f9f39dc04ba4255f5a8817af688383 6900e0d38ec37f0a5b6e8c62728e171e57b20e85 && git checkout -B drift-repro 7e61983e18f9f39dc04ba4255f5a8817af688383 && git merge --no-ff 6900e0d38ec37f0a5b6e8c62728e171e57b20e85
node scripts/docs-audit/affected-docs.mjs --json 7e61983e18f9f39dc04ba4255f5a8817af688383
|
…ct does not declare Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016WV4cykhsWAtSL6Sr4VWFG
…ng them Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016WV4cykhsWAtSL6Sr4VWFG
Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016WV4cykhsWAtSL6Sr4VWFG
|
domain:server#5 · os-elon-musk · session_016WV4cxHwXNcGcAHNerZsom Request: review · area A5 · head 6900e0d · 2026-11-14T22:19Z Fixes #33302. |
|
Contract-review-claim: session_016WV4cxDxAYxdtDhtR1kQQe · head 6900e0d · 2026-11-14T22:20:26Z |
Review: PASSreview#2 (server area pilot) · area A5 · Fixes #33302 · head What was checked (read-only: the diff, the card, the os-dev report 6885073938 and
Semver: Rulings on the report's open questions:
Nits (none blocking):
Nits only, so this is the final round. Generated by Claude Code |
|
domain:server#5 · os-elon-musk · session_016WV4cxHwXNcGcAHNerZsom ACCEPT · area A5 · head 6900e0d · 2026-11-14T22:22Z
|
Requested by Elon · project thread
Fixes #33302
Clause-②: no
Metadata-protocol: none
Skills-docs: none — no authorable key, value or metadata type moves; the change is which runtime doors announce an existing kernel event
Opened by
domain:server#5 · os-elon-musk · session_016WV4cykhsWAtSL6Sr4VWFG(area A5 of the server area-lease pilot), from claim comment 6884323409.维护者速读
POST /packages安装与PATCH /packages/:id/enable启用两条路由,在包进入服务后向内核宣告metadata:reloaded(载荷changed: ['app/ID'],与市场本地安装同一拼法)。安装每次落地都宣告;启用只在包原本处于停用时宣告。metadata:reloaded订阅者(岗位改名renamedFrom的任职人迁移、流程重同步、钩子/动作/翻译重同步)都听不到,要等下次重启。warn,不改变路由的应答。回滚即回退本 PR。packages/runtime/src/domains/packages.ts中新增的announcePackageReload与启用路由里的wasDisabled判定;packages/runtime/src/domains/packages-reload-announce.test.ts。pnpm --filter @objectstack/runtime exec vitest run --project local --maxWorkers=2 src/domains/packages-reload-announce.test.ts,预期 5 个用例全绿。What changes
packages/runtime/src/domains/packages.tsannouncePackageReload(deps, context, id, door), used only by the two handlers below. It callsdeps.announceKernelEvent(context, 'metadata:reloaded', { changed: ['app/ID'] }), the spelling the marketplace install-local door uses (announceHotInstallin@objectstack/cloud-connection). A subscriber failure is caught and logged once atwarnwith the restart that repairs it, the level the publish-drafts door and install-local use for the same announce. It never changes the door's answer.POST /packages: announces after the registry write and the durable state write, on both answers. That includes theenableOnInstalllifecycle refusal, which refuses the switch but not the install, whose row is already served.PATCH /packages/:id/enable: readsregistry.isPackageDisabled(id)beforeenablePackage(the predicateenablePackageitself asks before it tells its enable listeners). It announces only when the package was disabled, so an enable of an already-enabled package announces nothing.packages/runtime/src/domains/packages-reload-announce.test.ts: new pin file (5 cases)..changeset/33302-package-doors-announce-reload.md:@objectstack/runtimepatch.The A2 hunk in this file (open PR #33276, around line 2997, a different handler) is not touched.
Why
After the hot-install carry landed,
plugin-securitycarries the holders of a renamed position (renamedFrom) onmetadata:reloaded. Neither of these two doors announced that event, so a package they brought into service kept its renamed positions' holders on the old names until the next boot. The same went for every other subscriber of the event.Premise re-measured on
origin/main(9499dcc) through the real route before the fix: the same pin file withpackages.tsat that commit answers4 failed | 1 passed, and the holder assertions read{ e1: 'sales_rep', ... }and{ i1: 'field_rep' }: the holders stayed on the old names.One part of the card's premise is narrower than written.
ManifestSchemadeclares nopositionskey, so aPOST /packagesbody can never carry a position. A probe ofManifestSchema.safeParsewithpositionsanswersunrecognized_keys: ["positions"]. An authored package's positions are registered by a publish, and that publish already announcesposition/NAME. The install door puts a renamed position into service in one way only: an overwrite install withenableOnInstall: trueof a disabled package. The install-side holder pin therefore drives that path. A fresh install is pinned on the announcement itself.Tests
packages-reload-announce.test.tsuses a realObjectKernelwith the SQL driver (better-sqlite3:memory:),ObjectQLPlugin, the realSecurityPlugin, and anHttpDispatcherover that kernel. The holder move isplugin-security's own carry. A recorder hook only listens, and reads whether the registry holds the named package when the event arrives.sales_repis disabled, then enabled throughPATCH /packages/:id/enable. The holder moves tocrm_sales_rep, the control holder is untouched, and exactly one announcement{ changed: ['app/ID'] }arrives with the package registered.POST /packages: one announcement, with the package registered.enableOnInstall: trueof a disabled authored package whose published position renamesfield_rep: the holder moves toauthored_sales_rep, with one announcement.warn, naming the package.Green at d57ccec
Ablation: packages.ts restored to 9499dcc (predicted 4 failed | 1 passed)
Case 2 stays green in both legs: an already-enabled package announces nothing before or after the change.
Acceptance notes
packages/plugins/plugin-security/src/position-renamed-holder-carry.ts(module doc, "When it runs") still lists "the runtime's package install and enable routes" as doors that register positions without announcing. That sentence is now false. The file is outside this card's surface, so it is reported for the seat and not edited here.DELETE /packages/:idstill announce nothing. The install-local uninstall does announce the withdrawal. Whether these two should was left out of scope by the card, and the report covers it.Verification
Local verification after this head (typecheck, the runtime suite, the derived gate families and the
--ranreconciliation) is in theos-dev-reportcomment on #33302. CI check-runs are the authority for every family CI runs.Human Minimum
packages/specholds no runtime logic. (packages/specuntouched.)pnpm lintis CI's run.main, one pull request.packages/spectouched: not applicable.content/docs/references/,packages/*/CHANGELOG.mdorcontent/docs/releases/.Generated by Claude Code