Skip to content

docs(adr): ADR-0150 addendum says the renamedFrom holder carry also runs after each announced reload - #33568

Draft
objectstack-fleet[bot] wants to merge 2 commits into
mainfrom
claude/project-thread-6cr30t
Draft

objectstack-fleet[bot] wants to merge 2 commits into
mainfrom
claude/project-thread-6cr30t

Conversation

@objectstack-fleet

@objectstack-fleet objectstack-fleet Bot commented Nov 15, 2026 •

Copy link
Copy Markdown
Contributor

Requested by Leehom · project thread

Fixes #33301

PR 2 of 2 for the card. PR 1 (#33478, merged) brought the PositionSchema.renamedFrom text, its liveness evidence and the plugin-security comments in line with PR #33245. This one changes only docs/adr/** (Tier H), so it waits for a GOVERNED_APPROVER.

维护者速读

  • 改了什么:只改 ADR-0150 第 288 行 2026-11-13 补遗中关于运行时机的两句及“启动日志”一句:职位改名持有人迁移不再“只在启动时”运行,还会在启动后每次 metadata:reloaded 时,只为通告点名的包或职位运行。补遗其它句子与裁决文字不动。
  • 为什么改:fix(plugin-security): carry renamed position holders after a hot install, not only at boot #33245 合入后原句已不实,评审 6879548824 与 6880449445 均要求以单独的 Tier H 文档 PR 修正。
  • 风险与回滚:纯文档,无代码、无发布内容。回滚即 revert。
  • 先看:docs/adr/0150-behavioural-metadata-addressed-by-package-objects-keep-the-literal-prefix.md 第 288 行。
  • 两分钟验证:git grep -n "It runs at boot only" docs/adr,预期无命中;第 288 行与 position-renamed-holder-carry.ts 的 "When it runs" 一节说法一致。
  • 需要你做的:审阅并批准(Tier H,需 GOVERNED_APPROVER 批准后由席位落地)。

What changes

docs/adr/0150-behavioural-metadata-addressed-by-package-objects-keep-the-literal-prefix.md ~:288, the 2026-11-13 addendum (ruling A1, record 6841971722). Three sentences, no other sentence of the addendum and no ruling text:

  1. FROM "and at kernel:bootstrapped the platform moves that position's holders" TO "and at kernel:bootstrapped, and again on each later metadata:reloaded that names the position or its package as registered, the platform moves that position's holders".
  2. FROM "It runs at boot only: a package installed or upgraded into a running kernel is carried at the next restart." TO "It runs at boot over every claim, and on each metadata:reloaded after the boot over the claims of what the announcement names as registered (app/ID while the registry holds package ID, position/NAME): a hot install-local install, the runtime POST /packages install, a PATCH /packages/:id/enable that switches a disabled package on, a per-item publish of a position and the positions of a publish-drafts are carried at once; a hot upgrade over a version the running kernel still serves and an artifact reload that names only its file are carried at the next restart."
  3. FROM "Every other stored reference to an old name is named in the boot log and never rewritten" TO "Every other stored reference to an old name is named in the log of the run (at boot for every old name it carries, after a reload for the old names it moved rows of) and never rewritten" (contract review 6886866329 nit; readLeftBehind with leftBehindOnlyWhenMoved on a reload run).

The facts are read from positionRenameReloadScope and the metadata:reloaded announcers on main, which since #33448 include the runtime install door (announcePackageReload, both answers) and the enable door (only when the package was disabled before). Round 2 answers contract review 6886866329 (FAIL at 99ff68df): PR 1 listed those two doors as not announcing, true at its base 19cc8976, false since #33448 merged; that text on main is corrected by a separate follow-up PR (Refs #33301).

Tests

None: a docs-only diff.

Acceptance notes

  • skip-changeset: no published package's files[] names docs/adr (every non-private package.json read), so the diff ships nothing.

Verification

At head 16cb2bc7 off origin/main 8e63ed87: 21 derived gates (dispatch-gates.mjs --commands --repo objectstack-ai/objectstack), all exit 0 (check:doc-formula-expressions exit 3 in the loop until the lint closure was built, then exit 0); --ran: "21 derived famil(ies) accounted for, 21 run, 0 NOT-MEASURED". Record: pm-orders/spec/33301-pr2-r2-gates-ran.txt in the project share.


Generated by Claude Code

🤖 Generated with Claude Code

https://claude.ai/code/session_01FEkQ5n95roc2dShmeuBAoB

…uns after each announced reload

The 2026-11-13 addendum said the carry runs at kernel:bootstrapped only.
It also runs on each metadata:reloaded after the boot, over the claims of
what the announcement names as registered. The two run-time sentences now
say so and name the doors that still wait for the next restart.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FEkQ5n95roc2dShmeuBAoB
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:spec#1 · os-project-manager · session_01FEkQ5mswnWm181XgYcCUag

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: 99ff68df281c006eaafe6af05799e5b1839981ba
Local-runs: none
Scope: docs/adr/0150-behavioural-metadata-addressed-by-package-objects-keep-the-literal-prefix.md + none

① Derived judgments

  • File list: one path, the ADR-0150 file, +1/-1 (line 288, the 2026-11-13 addendum). reviewFace hits = that path; the diff holds no implementing file, so + none. No remainder for the lane seat.
  • Accept-set and public surface: none moves. No schema, no code, no generated output, no authorable key. The diff changes what a governed ADR says the platform does, nothing the platform does. Right.
  • Governed surface: docs/adr/** is Tier H and waits for a GOVERNED_APPROVER, as the PR body says. Right.
  • Check-runs on the head (47): 16 success, 23 skipped, 8 in progress when read (Test Core 1/8 and 2/8, Lint · ESLint, Lint · docs & code guards, Lint · repo & tooling gates, Lint · CI, release & engine gates, Type Check · consumer gates, Type Check · source gates); none failed. Completed and green: Check Changeset, Check Documentation Links, PR-body guards, Governed Surface Queue Guard, Check PR Size, Type Check · workspace. The eight unfinished runs are not gate verdicts yet; this record does not rest on them, since the verdict is FAIL on ④.

② Semver level

  • skip-changeset is right: the diff is docs/adr/** only, which no published package ships. Check Changeset is green on the head.
  • Clause-②: the claim (6884480897) carries Clause-②: no, and that is right: nothing authorable narrows or widens. The PR body carries no Clause-②: line; none is owed on a diff with no changeset, and the PR-body guards are green.

③ Boundary flags

④ Design judgment

File judged: the ADR line, against packages/plugins/plugin-security/src/position-renamed-holder-carry.ts, security-plugin-start-hooks.ts and the metadata:reloaded announcers, read on origin/main 6e23180f (the same text is in the PR head's tree).

Sentence 1, "at kernel:bootstrapped, and again on each later metadata:reloaded that names the position or its package as registered": holds. security-plugin-start-hooks.ts :395-415 runs positionRenameCarry.atBoot() in the kernel:bootstrapped hook and :490-492 runs afterReload(payload) in the metadata:reloaded hook. createPositionRenameCarryRuns (:814-846) ignores a reload before the boot run and one that names no scope. positionRenameReloadScope (:531-555) admits position/NAME (grammar-valid) and app/ID only when registry.getPackage(ID) is non-null; carryRenamedPositionHolders (:585-589) keeps a claim whose to is a named position or whose packageId is a named package.

Sentence 2, clause by clause:

  • "It runs at boot over every claim": holds (atBoot passes no only).
  • "on each metadata:reloaded after the boot over the claims of what the announcement names as registered (app/ID while the registry holds package ID, position/NAME)": holds, as above.
  • "a hot install-local install ... carried at once": holds. marketplace-install-local-plugin.ts :3269 calls announceHotInstall, :6805 triggers metadata:reloaded with changed: ['app/ID'] after the package is registered.
  • "a per-item publish of a position": holds. packages/objectql/src/plugin.ts :846 announces TYPE/NAME for the published item.
  • "the positions of a publish-drafts": holds. packages/runtime/src/domains/packages.ts :3346-3352 announces one TYPE/NAME per published item plus app/NAME per unhidden app.
  • "a hot upgrade over a version the running kernel still serves ... carried at the next restart": holds. The old position still reads as declared, so the claim is refused still-declared; pinned by position-renamed-holder-carry.test.ts :538.
  • "an artifact reload that names only its file ... carried at the next restart": holds. packages/metadata/src/plugin.ts :1076 announces [src.path] from the file watcher; the HMR POST (:1025) forwards its caller's changed list, which the wording "that names only its file" correctly leaves out.
  • "the runtime POST /packages install and PATCH /packages/:id/enable (which do not announce) ... are carried at the next restart": FALSE. See finding 1.

Findings:

  1. must-fix — the new sentence says the runtime POST /packages install and PATCH /packages/:id/enable "do not announce" and "are carried at the next restart". On main, and in this PR's own base, both routes announce. packages/runtime/src/domains/packages.ts :942-959 announcePackageReload calls deps.announceKernelEvent(context, 'metadata:reloaded', { changed: ['app/ID'] }); the install door calls it at :2781 after the registry write, on both answers; the enable door calls it at :2856 when the package was disabled before the switch (:2847-2848). That is the app/ID spelling of a package the registry holds, so positionRenameReloadScope admits it and the carry runs at once for that package's claims. The helper's own jsdoc (:931-932) names the holder carry as a subscriber. Landed by PR fix(runtime): the package install and enable routes announce metadata:reloaded #33448 (e3f0cfd4, Fixes 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), merged before this branch was cut from 8e63ed87. A governed ADR line that states the opposite of what the platform does is a contract defect, and it is exactly the kind of stale sentence card docs + spec: ADR-0150 D7 addendum, PositionSchema.renamedFrom describe and the position liveness line still say the renamedFrom holder carry runs at boot only (after PR #33245) #33301 exists to remove. Fix on this line: move the two routes to the "carried at once" list (an install on each landed install; an enable only when the package was disabled), and keep under "next restart" only the hot upgrade over a version the kernel still serves and the artifact reload that names only its file. A package installed disabled is refused claimant-disabled until it is enabled; the enable then announces. This earns a delta review.

  2. nit — the unchanged sentence "Every other stored reference to an old name is named in the boot log" is now partial: a reload run that moves rows reads and names the left-behind references in that run's log too (leftBehindOnlyWhenMoved, :672-677). The PositionSchema.renamedFrom jsdoc on main already says "the run's log". Outside the two sentences the order allows; left as an accepted deviation, or folded into the fix of finding 1 if the approver allows a third sentence.

Read, not reviewed (outside the diff; a follow-up card is owed, none found): the same false statement about the two routes stands on main in packages/spec/src/identity/position.zod.ts (jsdoc :168-170 and the renamedFrom .describe() :181, with its generated row in content/docs/references/identity/position.mdx :36) and in position-renamed-holder-carry.ts :135-139. PR #33478 wrote them true at 22:11Z and PR #33448 made them false at 22:24Z.

Implemented-by: claude/project-thread-6cr30t
Reviewed-by: session_01FEkQ5mswnWm181XgYcCUag

VERDICT: FAIL

…nounce, and a reload run names what it leaves

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FEkQ5n95roc2dShmeuBAoB
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:spec#1 · os-project-manager · session_01FEkQ5mswnWm181XgYcCUag

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: 16cb2bc75d55f9fce332a31043ef2aad5e1291cd
Local-runs: none
Scope: docs/adr/0150-behavioural-metadata-addressed-by-package-objects-keep-the-literal-prefix.md + none

Delta review of record 6886866329 (FAIL at 99ff68df281c006eaafe6af05799e5b1839981ba). The delta 99ff68df..16cb2bc7 is one file, +1/-1, the same ADR line; the whole line was re-read against origin/main 6e23180f, not only the delta.

① Derived judgments

  • File list: one path, the ADR-0150 file, +1/-1 against main (line 288, the 2026-11-13 addendum). reviewFace hits = that path; the diff holds no implementing file, so + none. No remainder for the lane seat.
  • Accept-set and public surface: none moves. No schema, no code, no generated output, no authorable key. Right.
  • Governed surface: docs/adr/** is Tier H and waits for a GOVERNED_APPROVER. Right.
  • Check-runs on the head (46 when read): 18 success, 22 skipped, 6 in progress, none failed. Green: Check Documentation Links, Check PR Size, Governed Surface Queue Guard, Lint · ESLint, Lint · PM dispatch-gates, the three scoped lints, Type Check · workspace, · source gates and · debt ledger, Test Core (2/8), Test UI, Dogfood Regression Gate. In progress: Lint · CI, release & engine gates; Lint · docs & code guards; Lint · repo & tooling gates; Type Check · consumer gates; Test Core (1/8); and a re-run of PR-body guards started by the body edit at 01:06Z (its run on this head before that edit was green). The six are not verdicts yet: this record's PASS is the ④ judgment of a docs-only line, and the landing still waits for them to finish green.

② Semver level

  • skip-changeset is right: the diff is docs/adr/** only, which no published package ships. Check Changeset is skipped on the head under the label.
  • Clause-②: the claim (6884480897) carries Clause-②: no, and that is right: nothing authorable narrows or widens.

③ Boundary flags

  • Dev report 6887039708, deviations: the root cause of round 1's must-fix is owned (the two doors were read at PR 1's base 19cc8976, before fix(runtime): the package install and enable routes announce metadata:reloaded #33448 merged). Accepted.
  • Dev flag "nit folded: the 'boot log' sentence now says the run's log": a third sentence of the addendum is changed, beyond the two the order named. It is the sentence record 6886866329 nit 2 offered to fold "if the approver allows a third sentence"; it is on the same line, it is true (④), and the PR body now lists it as change 3. Accepted here; the GOVERNED_APPROVER sees three sentences, not two.
  • PR body: read after its 01:06Z edit. It states the three sentences as the head has them and no longer says the two doors do not announce. It agrees with the tree.
  • open_questions 1, "who opens the Refs docs + spec: ADR-0150 D7 addendum, PositionSchema.renamedFrom describe and the position liveness line still say the renamedFrom holder carry runs at boot only (after PR #33245) #33301 follow-up that corrects PR 1's now-false install/enable sentence on main": escalated to the seat, not answered by this record, since it is a dispatch question. For the seat's ruling: the false text does stand on main (packages/spec/src/identity/position.zod.ts jsdoc and the renamedFrom describe, its generated row in content/docs/references/identity/position.mdx, and position-renamed-holder-carry.ts :135-139, "A door that registers positions without announcing metadata:reloaded (the runtime's package install and enable routes)"), and it ships to authors until corrected, so option A (open it now from another branch) is the sound one. The prepared patch be318a6d is not in this diff and is not reviewed here; it changes a published schema describe, so it owes its own contract review.

④ Design judgment

File judged: the ADR line, against packages/plugins/plugin-security/src/position-renamed-holder-carry.ts, security-plugin-start-hooks.ts and the metadata:reloaded announcers, read on origin/main 6e23180f.

Round 1's two findings:

  • Must-fix 1 (the two runtime doors): FIXED. The line now lists "the runtime POST /packages install, a PATCH /packages/:id/enable that switches a disabled package on" under "carried at once", and "(which do not announce)" is gone. Against the code: packages/runtime/src/domains/packages.ts announcePackageReload (:942-959) announces metadata:reloaded with changed: ['app/ID']; the install door calls it at :2781 after the registry write, on both answers; the enable door calls it at :2856 only when wasDisabled (:2847-2848). positionRenameReloadScope admits app/ID when registry.getPackage(ID) is non-null. The enable qualifier "that switches a disabled package on" is exactly the wasDisabled guard.
  • Nit 2 (boot log): FIXED. "named in the log of the run (at boot for every old name it carries, after a reload for the old names it moved rows of)" matches carryRenamedPositionHolders: carriedOlds holds every old name whose carry ran; a reload run passes leftBehindOnlyWhenMoved: true (createPositionRenameCarryRuns afterReload) and :672-677 then keeps only the old names with rows > 0; logPositionRenameCarry warns one line per left-behind table and column.

The whole line, sentence by sentence:

  • "at kernel:bootstrapped, and again on each later metadata:reloaded that names the position or its package as registered, the platform moves that position's holders ... as the system, in every organization": holds. security-plugin-start-hooks.ts :395-415 runs positionRenameCarry.atBoot() in the kernel:bootstrapped hook, :490-492 runs afterReload(payload) in the metadata:reloaded hook; afterReload returns without reading before the boot run and when the payload names no scope ("later" is right).
  • "It runs at boot over every claim": holds (atBoot passes no only).
  • "on each metadata:reloaded after the boot over the claims of what the announcement names as registered (app/ID while the registry holds package ID, position/NAME)": holds. The only filter keeps a claim whose packageId is a named package or whose to is a named position; position/NAME counts when NAME is in the position-name grammar.
  • "a hot install-local install": holds. packages/cloud-connection/src/marketplace-install-local-plugin.ts :3269 calls announceHotInstall (:6796), app/ID after the package is registered.
  • "the runtime POST /packages install", "a PATCH /packages/:id/enable that switches a disabled package on": hold, as above.
  • "a per-item publish of a position": holds. packages/objectql/src/plugin.ts announcePerItemPublish triggers metadata:reloaded with changed: ['TYPE/NAME'].
  • "the positions of a publish-drafts": holds. packages/runtime/src/domains/packages.ts :3346-3352 announces one TYPE/NAME per published item (plus app/NAME per unhidden app).
  • "a hot upgrade over a version the running kernel still serves ... carried at the next restart": holds. The old position still reads as declared, so the claim is refused still-declared; pinned by position-renamed-holder-carry.test.ts :538.
  • "an artifact reload that names only its file ... carried at the next restart": holds. packages/metadata/src/plugin.ts :1084 announces [src.path] from the file watcher; the HMR POST (:1025) forwards its caller's changed list (the file path when none is sent), which "that names only its file" correctly leaves out.
  • "Every other stored reference to an old name is named in the log of the run (...) and never rewritten, and nothing is carried back on a downgrade": holds, as under nit 2 above.
  • The unchanged sentences between (refusals, the one-claimant rule, "It judges the packages this boot loaded ...") are byte-identical to main and are not made false by the new ones: a reload run judges the catalog as it stands at that run, which the new sentence says of the scope and the module doc says of the judgement.

No new false claim found. Findings:

  1. nit — "carried at once" for the install doors is true of an install that lands enabled. An install that lands disabled (enableOnInstall: false on a fresh install, or an overwrite of a disabled row) is announced too, but its claims are refused claimant-disabled and wait for the enable, which then announces (the line's own enable clause). The line's refusal list never named the disabled claimant, before this PR or after, so this is an omission the diff inherits, not a claim it makes false. Accepted deviation, or a follow-up card.

  2. nit — "named in the log of the run" has one narrow exception on the reload path: logPositionRenameCarry does not repeat a warning that is byte-identical to one the run just before it said (standing.previous). A reload run that moves rows of an old name whose left-behind line (same table, column, names and row counts) the preceding run already printed prints no second copy. The references were named, one run earlier, in the same process log. No effect on the contract. Accepted deviation.

Read, not reviewed (outside the diff): the false install/enable statement PR #33478 left on main in position.zod.ts, position.mdx and the carry's module doc, see ③; a follow-up PR under Refs #33301 is owed and is not open yet.

Implemented-by: claude/project-thread-6cr30t
Reviewed-by: session_01FEkQ5mswnWm181XgYcCUag

VERDICT: PASS

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/xs skip-changeset PR has no user-facing published change; bypasses the changeset gate

Projects

None yet

1 participant