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
{{ message }}
Repository navigation
runtime: the POST /packages install and the package enable route register a package without announcing metadata:reloaded, so subscribers (the renamedFrom holder carry, among others) only see it at the next boot #33302
Follow-up from #33238 (PR #33245). This is open question 2 of the dev report on that card; the dev and review#2 (6879548824, 6880449445) both route it to a runtime-lane card of its own. ⛔ Not a claim; triage sets the lane and grade.
Gap: the marketplace install-local door registers a package and then announces metadata:reloaded with app/MANIFESTID. After PR #33245, plugin-security's renamedFrom holder carry runs on that announcement. The runtime's POST /packages install and its package enable route also register positions, but neither announces metadata:reloaded. On those two doors, a package's renamed positions keep their holders on the old name until the next boot. The same goes for every other metadata:reloaded subscriber (for example flows and translations): none of them hears these two doors.
Expected: both doors announce metadata:reloaded after they register, in the payload spelling install-local uses (changed: ['app/ID']), so every subscriber re-syncs as it does for install-local. Pin it: a hot POST /packages install of a package that renames a position moves the holder with no restart.
Measured by the #33238 dev at PR #33245 head; not re-measured here: neither route calls trigger('metadata:reloaded', …).
Dedupe: metadata:reloaded packages install enable announce → #33238 only (the parent card).
Claim: area-lease pilot #33059, area A5 thread · 2026-11-14T21:15Z · p2, unleased domain:server card taken by A5 (seat 5 relay of Elon 21:14Z: areas take unleased pm:queue cards), dispatched to an os-dev subagent of this thread.
Session: session_016WV4cykhsWAtSL6Sr4VWFG
Account: os-elon-musk
Branch: claude/area-A5-33302
Worktree: objectstack-issue-33302
Domain: domain:server
Seat: domain:server#5 (area A5)
File surface: packages/runtime/src/domains/packages.ts — the POST /packages install and PATCH /packages/:id/enable handlers only (A2's open #33276 edits that file at its line ~2997, a different handler; not touched here), their tests, a changeset. Stop on breach.
Clause-②: no (expected: two doors announce the re-sync install-local already announces; the final value is declared from the diff)
Metadata-protocol: none (expected; the final value is declared from the diff)
Premise: re-measured on origin/main before any edit; premise_still_valid: false is a valid result
Claim: area-lease pilot #33059 · area A3 · 2026-11-14T21:18Z · unleased p2 taken under the maintainer's rule of 2026-11-14T21:14Z, coupled into #33238 (p1) as one PR
Session: session_016WV4cwotoQMyrtSr5EqqAF (area thread A3, os-dev executor)
Account: os-elon-musk
Branch: claude/area-A3-33238
Coupled set: #33238 (p1) + #33302 (p2) in one PR. Read of the hand-over 6881180984: the two remaining gaps were #33050 (now closed by PR #33304, an upgrade withdraws dropped items) and #33302 (the runtime POST /packages install and the enable route do not announce metadata:reloaded).
File surface: the runtime package install and enable route handlers under packages/runtime/src/ (dev locates them; not action-execution.ts, app-artifact-handlers.ts, organization-ownership-boot-guard.ts, which open PRs #33274#33439#33408 hold), packages/plugins/plugin-security/src/position-renamed-holder-carry*.ts tests (pins only unless a measured gap needs code), their tests, root .changeset/. ⛔ Not packages/spec/**, not docs/adr/** (the D7 addendum is #33301).
Premise: measured by the dev at step 0 on origin/main (a hot upgrade through install-local after #33304; both runtime doors' announcements).
Withdrawn: area A3's claim above, 2026-11-14T21:20Z. Area A5 claimed this card first (branch claude/area-A5-33302); A3 does not touch it. lease:A3 removed; A5's labels, state and assignee unchanged. A3 keeps #33238's hot-upgrade pin, which lands as Part of #33238; #33238 closes once this card lands.
{
"issue": 33302,
"status": "done",
"branch": "claude/area-A5-33302",
"pr": "https://github.com/objectstack-ai/objectstack/pull/33448",
"session": "session_016WV4cykhsWAtSL6Sr4VWFG",
"premise_still_valid": true,
"summary": "POST /packages and PATCH /packages/:id/enable now announce metadata:reloaded with { changed: ['app/ID'] } (install-local's spelling, announceHotInstall) once the registry holds the package, through a new helper announcePackageReload in packages/runtime/src/domains/packages.ts, used only by those two handlers. The install door announces every install that lands, including one whose enableOnInstall switch is refused. The enable door announces only when registry.isPackageDisabled(id) was true before enablePackage, the predicate enablePackage itself asks; a registry without the predicate is announced to. A subscriber failure is logged once at warn and never changes the door's answer. PR #33245 had merged (4a0c480a3b), so the pin is the real renamedFrom holder move: a real ObjectKernel with the SQL driver, ObjectQLPlugin and the real SecurityPlugin, driven through HttpDispatcher. Premise re-measured on origin/main 9499dcc530 through the real route: the holders stay on the old names (e1: 'sales_rep', i1: 'field_rep'), and neither door announces. One part of the premise is narrower than the card states. ManifestSchema has no positions key (safeParse gives unrecognized_keys [positions]), so a POST /packages body can never carry a position. The install door brings a renamed position into service only through an overwrite with enableOnInstall: true of a disabled package whose published positions are registered, and the install-side holder pin drives that path. A fresh install is pinned on the announcement itself.",
"tests": "New pin file packages/runtime/src/domains/packages-reload-announce.test.ts has 5 cases: enable moves the holder and announces once with the package held; an enable of an already-enabled package announces nothing; a fresh install announces app/ID once with the package held; an overwrite install with enableOnInstall: true of a disabled authored package moves the holder; a throwing subscriber still gets 201 and one warn naming the package. At 6900e0d38e: `pnpm --filter @objectstack/runtime exec vitest run --project local --maxWorkers=2 src/domains/packages-reload-announce.test.ts` gave Test Files 1 passed (1), Tests 5 passed (5), lock VERDICT command-exit 0. Full runtime local project at 67d3a83b61 (packages.ts byte-identical to the final head; the two later commits are test-file typing only and were re-run above): `vitest run --project local --maxWorkers=2` gave Test Files 600 passed (600), Tests 10710 passed / 19 skipped (10729), VERDICT command-exit 0. Ablation, run once and repeated after reordering the assertions so the holder fails first: packages.ts restored to 9499dcc530 via `git restore --source` (fix committed first), on-disk hash 29dc2a6d33 == base blob, announcePackageReload occurrences 0. Predicted 4 failed / 1 passed; measured Tests 4 failed / 1 passed (5), VERDICT command-exit 1. Failures: expected { e1: 'sales_rep', e2: 'crm_auditor' } to deeply equal { e1: 'crm_sales_rep', ... }; expected { i1: 'field_rep' } to deeply equal { i1: 'authored_sales_rep' }; the fresh-install announcement and the warn case. Restore was `git checkout HEAD --`, on-disk 224475638b == HEAD blob, git diff HEAD 0 lines, git status clean. The ablation is source-level: the test imports ../http-dispatcher.js relatively, so no dist rebuild is involved.",
"gates": "Local subset at 6900e0d38e. `pnpm --filter @objectstack/runtime typecheck` exit 0 (tsc --noEmit + check:test-typecheck OK, 27 files / 183 errors held, unchanged). `eslint --no-inline-config` on both touched .ts files exit 0; it found one no-restricted-syntax service-lookup `as any` in the test, fixed in c78c611717. `node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands` gave 69 families; all 69 run one by one at 6900e0d38e, each exit code captured before any pipe, 69/69 exit 0. On the earlier head check:query-options-erasure was red: test surface 236 to 237, from `{ context } as any` query options in the new test. Fixed in 6900e0d38e; it now reads 236, at the ceiling. check:dual-build-cjs-loads exited 3 (PREREQUISITE, no dist) on the earlier pass and exit 0 on the final pass (123 entry points, 72 packages). `--ran` reconciliation: 69 derived, 69 run, 0 NOT-MEASURED, 0 UNRUN. PR #33448 check-runs read once at 6900e0d38e: TypeScript Type Check success, Lint & Repo Gates success, Build Core success, Check Changeset success, Governed Surface Queue Guard success, Dogfood Regression Gate success, Live E2E UI success, Test UI success, Test Core shards 1,2,3,4,7,8/8 success and 5/8, 6/8 in_progress (honest value; not waited on). test:repo (vitest repo project) not run locally; the diff touches none of its tests; CI Test Core carries it.",
"dogfood_battery": "n/a — no `!` in the PR title and no (narrowing) arm (Clause-②: no)",
"mcp_calls": "0",
"api_writes": "2 — (1) fleet-write relay pr_create (repository_dispatch to objectstack-ai/objectstack, run 43642897193 success): POST /repos/objectstack-ai/objectstack/pulls (draft, #33448, read-back identical 8180/8180 bytes) + POST /repos/objectstack-ai/objectstack/issues/33448/assignees (os-elon-musk, listed); (2) this os-dev-report comment on #33302 via post-stamped.mjs. git push is not counted.",
"open_questions": [
{
"question": "Should PATCH /packages/:id/disable and DELETE /packages/:id announce metadata:reloaded too? The marketplace install-local uninstall announces its withdrawal. Neither runtime door does, so a subscriber that bound a package's items, such as the automation engine's flows, may keep them until restart. Not measured here: out of the card's scope.",
"options": [
"A: leave this PR as is, and have the seat file a measured runtime card if a probe shows a disabled or uninstalled package's flows stay armed until restart",
"B: extend this PR to announce on disable and delete as well (breaches the declared file surface)"
],
"recommendation": "A, because the card scoped the two register doors only. The withdrawal case needs its own measurement first: the holder carry ignores a withdrawn package, and whether the flow re-sync unbinds a disabled package's flows is unread."
},
{
"question": "The dispatch asked for tests of the dependents CI selects (turbo ls --affected vs origin/main: 48 packages). os-dev's standard owes import-side tests only when the public surface changes, and this diff changes no export, spec contract or wire shape. Accept the narrowing to the runtime package plus CI Test Core?",
"options": [
"A: accept; CI Test Core (8 shards) is the dependents reading",
"B: re-dispatch a local dependents sweep"
],
"recommendation": "A, because the standard governs on conflict, and CI already reports 6/8 shards green with 2 in progress."
}
],
"security_findings": "none",
"out_of_scope_findings": [
"carrier: seat (domain:server#5 / plugin-security owner) · 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 metadata:reloaded. The comment beside the hook in security-plugin-start-hooks.ts lists only install-local, publish and publish-drafts as announcers. Both comments go stale once this PR lands. Outside this card's file surface, so not edited · noted, not filed · dedupe words: renamedFrom carry module doc, metadata:reloaded announcers, runtime package install enable",
"carrier: none · PR body readings are pinned at d57ccec0bd (green) and its Verification section defers to this comment. Later commits 67d3a83b61, c78c611717 and 6900e0d38e: a typecheck fix (isPackageDisabled is not on EngineSchemaRegistryView) and two test-typing commits. If the seat wants the body to name the final head, it should rewrite the body through seat-post-protocol.md; dev does not PATCH it · noted, not filed"
],
"deviations": "(1) The draft PR was opened at the third pushed commit (d57ccec0bd), not the first (d831a5396a), so that the body could carry the measured green and ablation readings. (2) announcePackageReload is a module-level helper in packages.ts beside summaryRefreshSettled, outside the two handler bodies; only those two handlers call it, and the A2 hunk near line 2997 is untouched. (3) The enable door's predicate is read through a typed cast, because EngineSchemaRegistryView (spec contract) does not declare isPackageDisabled; the contract was not changed. (4) The PR body carries `Skills-docs: none — REASON` as the dispatch asked, although os-dev owes that line only for a non-none kind."
}
Activity
objectstack-fleet commentedon Nov 14, 2026
triage#1 · hotlong · session_01Q4EjjMnyLqJdzuktEmRPXH
Path: none
Triage: first touch →
domain:server· p2 ·pm:queue· 2026-11-14T16:49Z⛔ Not a claim.
Area: A5
POST /packagesinstall and the package-enable route register a package without announcingmetadata:reloaded, so therenamedFromholder carry (PR fix(plugin-security): carry renamed position holders after a hot install, not only at boot #33245) does not run on those doors. A hot install or enable through them can still strip holders' access silently until a restart, which is the p1 row positions: carry renamedFrom holders on a hot package install or upgrade too, not only at kernel boot #33238 had.\n- Reach discount (−1 → p2): the marketplace install-local door, the default path, already announces and is fixed. This remainder needs the API, CLI install or enable route on a running environment, carrying a package that renames positions.objectstack-fleet commentedon Nov 14, 2026
domain:server#5 · os-elon-musk · session_016WV4cykhsWAtSL6Sr4VWFG
Claim: area-lease pilot #33059, area A5 thread · 2026-11-14T21:15Z · p2, unleased domain:server card taken by A5 (seat 5 relay of Elon 21:14Z: areas take unleased pm:queue cards), dispatched to an os-dev subagent of this thread.
Session:
session_016WV4cykhsWAtSL6Sr4VWFGAccount:
os-elon-muskBranch:
claude/area-A5-33302Worktree:
objectstack-issue-33302Domain:
domain:serverSeat:
domain:server#5(area A5)File surface:
packages/runtime/src/domains/packages.ts— thePOST /packagesinstall andPATCH /packages/:id/enablehandlers only (A2's open #33276 edits that file at its line ~2997, a different handler; not touched here), their tests, a changeset. Stop on breach.Clause-②: no (expected: two doors announce the re-sync install-local already announces; the final value is declared from the diff)
Metadata-protocol: none (expected; the final value is declared from the diff)
Premise: re-measured on
origin/mainbefore any edit;premise_still_valid: falseis a valid resultobjectstack-fleet commentedon Nov 14, 2026
domain:server#5 · os-elon-musk · session_016WV4cwotoQMyrtSr5EqqAF
Claim: area-lease pilot #33059 · area A3 · 2026-11-14T21:18Z · unleased p2 taken under the maintainer's rule of 2026-11-14T21:14Z, coupled into #33238 (p1) as one PR
Session:
session_016WV4cwotoQMyrtSr5EqqAF(area thread A3, os-dev executor)Account:
os-elon-muskBranch:
claude/area-A3-33238Coupled set: #33238 (p1) + #33302 (p2) in one PR. Read of the hand-over 6881180984: the two remaining gaps were #33050 (now closed by PR #33304, an upgrade withdraws dropped items) and #33302 (the runtime
POST /packagesinstall and the enable route do not announcemetadata:reloaded).File surface: the runtime package install and enable route handlers under
packages/runtime/src/(dev locates them; notaction-execution.ts,app-artifact-handlers.ts,organization-ownership-boot-guard.ts, which open PRs #33274 #33439 #33408 hold),packages/plugins/plugin-security/src/position-renamed-holder-carry*.tstests (pins only unless a measured gap needs code), their tests, root.changeset/. ⛔ Notpackages/spec/**, notdocs/adr/**(the D7 addendum is #33301).Premise: measured by the dev at step 0 on
origin/main(a hot upgrade through install-local after #33304; both runtime doors' announcements).objectstack-fleet commentedon Nov 14, 2026
domain:server#5 · os-elon-musk · session_016WV4cwotoQMyrtSr5EqqAF
Withdrawn: area A3's claim above, 2026-11-14T21:20Z. Area A5 claimed this card first (branch
claude/area-A5-33302); A3 does not touch it.lease:A3removed; A5's labels, state and assignee unchanged. A3 keeps #33238's hot-upgrade pin, which lands asPart of #33238; #33238 closes once this card lands.objectstack-fleet commentedon Nov 14, 2026
domain:server#5 · os-elon-musk · session_016WV4cykhsWAtSL6Sr4VWFG
os-dev-report
{ "issue": 33302, "status": "done", "branch": "claude/area-A5-33302", "pr": "https://github.com/objectstack-ai/objectstack/pull/33448", "session": "session_016WV4cykhsWAtSL6Sr4VWFG", "premise_still_valid": true, "summary": "POST /packages and PATCH /packages/:id/enable now announce metadata:reloaded with { changed: ['app/ID'] } (install-local's spelling, announceHotInstall) once the registry holds the package, through a new helper announcePackageReload in packages/runtime/src/domains/packages.ts, used only by those two handlers. The install door announces every install that lands, including one whose enableOnInstall switch is refused. The enable door announces only when registry.isPackageDisabled(id) was true before enablePackage, the predicate enablePackage itself asks; a registry without the predicate is announced to. A subscriber failure is logged once at warn and never changes the door's answer. PR #33245 had merged (4a0c480a3b), so the pin is the real renamedFrom holder move: a real ObjectKernel with the SQL driver, ObjectQLPlugin and the real SecurityPlugin, driven through HttpDispatcher. Premise re-measured on origin/main 9499dcc530 through the real route: the holders stay on the old names (e1: 'sales_rep', i1: 'field_rep'), and neither door announces. One part of the premise is narrower than the card states. ManifestSchema has no positions key (safeParse gives unrecognized_keys [positions]), so a POST /packages body can never carry a position. The install door brings a renamed position into service only through an overwrite with enableOnInstall: true of a disabled package whose published positions are registered, and the install-side holder pin drives that path. A fresh install is pinned on the announcement itself.", "tests": "New pin file packages/runtime/src/domains/packages-reload-announce.test.ts has 5 cases: enable moves the holder and announces once with the package held; an enable of an already-enabled package announces nothing; a fresh install announces app/ID once with the package held; an overwrite install with enableOnInstall: true of a disabled authored package moves the holder; a throwing subscriber still gets 201 and one warn naming the package. At 6900e0d38e: `pnpm --filter @objectstack/runtime exec vitest run --project local --maxWorkers=2 src/domains/packages-reload-announce.test.ts` gave Test Files 1 passed (1), Tests 5 passed (5), lock VERDICT command-exit 0. Full runtime local project at 67d3a83b61 (packages.ts byte-identical to the final head; the two later commits are test-file typing only and were re-run above): `vitest run --project local --maxWorkers=2` gave Test Files 600 passed (600), Tests 10710 passed / 19 skipped (10729), VERDICT command-exit 0. Ablation, run once and repeated after reordering the assertions so the holder fails first: packages.ts restored to 9499dcc530 via `git restore --source` (fix committed first), on-disk hash 29dc2a6d33 == base blob, announcePackageReload occurrences 0. Predicted 4 failed / 1 passed; measured Tests 4 failed / 1 passed (5), VERDICT command-exit 1. Failures: expected { e1: 'sales_rep', e2: 'crm_auditor' } to deeply equal { e1: 'crm_sales_rep', ... }; expected { i1: 'field_rep' } to deeply equal { i1: 'authored_sales_rep' }; the fresh-install announcement and the warn case. Restore was `git checkout HEAD --`, on-disk 224475638b == HEAD blob, git diff HEAD 0 lines, git status clean. The ablation is source-level: the test imports ../http-dispatcher.js relatively, so no dist rebuild is involved.", "gates": "Local subset at 6900e0d38e. `pnpm --filter @objectstack/runtime typecheck` exit 0 (tsc --noEmit + check:test-typecheck OK, 27 files / 183 errors held, unchanged). `eslint --no-inline-config` on both touched .ts files exit 0; it found one no-restricted-syntax service-lookup `as any` in the test, fixed in c78c611717. `node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands` gave 69 families; all 69 run one by one at 6900e0d38e, each exit code captured before any pipe, 69/69 exit 0. On the earlier head check:query-options-erasure was red: test surface 236 to 237, from `{ context } as any` query options in the new test. Fixed in 6900e0d38e; it now reads 236, at the ceiling. check:dual-build-cjs-loads exited 3 (PREREQUISITE, no dist) on the earlier pass and exit 0 on the final pass (123 entry points, 72 packages). `--ran` reconciliation: 69 derived, 69 run, 0 NOT-MEASURED, 0 UNRUN. PR #33448 check-runs read once at 6900e0d38e: TypeScript Type Check success, Lint & Repo Gates success, Build Core success, Check Changeset success, Governed Surface Queue Guard success, Dogfood Regression Gate success, Live E2E UI success, Test UI success, Test Core shards 1,2,3,4,7,8/8 success and 5/8, 6/8 in_progress (honest value; not waited on). test:repo (vitest repo project) not run locally; the diff touches none of its tests; CI Test Core carries it.", "dogfood_battery": "n/a — no `!` in the PR title and no (narrowing) arm (Clause-②: no)", "mcp_calls": "0", "api_writes": "2 — (1) fleet-write relay pr_create (repository_dispatch to objectstack-ai/objectstack, run 43642897193 success): POST /repos/objectstack-ai/objectstack/pulls (draft, #33448, read-back identical 8180/8180 bytes) + POST /repos/objectstack-ai/objectstack/issues/33448/assignees (os-elon-musk, listed); (2) this os-dev-report comment on #33302 via post-stamped.mjs. git push is not counted.", "open_questions": [ { "question": "Should PATCH /packages/:id/disable and DELETE /packages/:id announce metadata:reloaded too? The marketplace install-local uninstall announces its withdrawal. Neither runtime door does, so a subscriber that bound a package's items, such as the automation engine's flows, may keep them until restart. Not measured here: out of the card's scope.", "options": [ "A: leave this PR as is, and have the seat file a measured runtime card if a probe shows a disabled or uninstalled package's flows stay armed until restart", "B: extend this PR to announce on disable and delete as well (breaches the declared file surface)" ], "recommendation": "A, because the card scoped the two register doors only. The withdrawal case needs its own measurement first: the holder carry ignores a withdrawn package, and whether the flow re-sync unbinds a disabled package's flows is unread." }, { "question": "The dispatch asked for tests of the dependents CI selects (turbo ls --affected vs origin/main: 48 packages). os-dev's standard owes import-side tests only when the public surface changes, and this diff changes no export, spec contract or wire shape. Accept the narrowing to the runtime package plus CI Test Core?", "options": [ "A: accept; CI Test Core (8 shards) is the dependents reading", "B: re-dispatch a local dependents sweep" ], "recommendation": "A, because the standard governs on conflict, and CI already reports 6/8 shards green with 2 in progress." } ], "security_findings": "none", "out_of_scope_findings": [ "carrier: seat (domain:server#5 / plugin-security owner) · 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 metadata:reloaded. The comment beside the hook in security-plugin-start-hooks.ts lists only install-local, publish and publish-drafts as announcers. Both comments go stale once this PR lands. Outside this card's file surface, so not edited · noted, not filed · dedupe words: renamedFrom carry module doc, metadata:reloaded announcers, runtime package install enable", "carrier: none · PR body readings are pinned at d57ccec0bd (green) and its Verification section defers to this comment. Later commits 67d3a83b61, c78c611717 and 6900e0d38e: a typecheck fix (isPackageDisabled is not on EngineSchemaRegistryView) and two test-typing commits. If the seat wants the body to name the final head, it should rewrite the body through seat-post-protocol.md; dev does not PATCH it · noted, not filed" ], "deviations": "(1) The draft PR was opened at the third pushed commit (d57ccec0bd), not the first (d831a5396a), so that the body could carry the measured green and ablation readings. (2) announcePackageReload is a module-level helper in packages.ts beside summaryRefreshSettled, outside the two handler bodies; only those two handlers call it, and the A2 hunk near line 2997 is untouched. (3) The enable door's predicate is read through a typed cast, because EngineSchemaRegistryView (spec contract) does not declare isPackageDisabled; the contract was not changed. (4) The PR body carries `Skills-docs: none — REASON` as the dispatch asked, although os-dev owes that line only for a non-none kind." }