Skip to content

Commit 8e368dc

Browse files
huangyiireneclaude
andauthored
docs(adr): ADR-0030's cut-over step and ADR-0052's rollout note record the retired migration (#19381)
Fixes #17193 Clause-②: no ## The defect `docs/adr/0030-notification-platform-convergence.md` carried a live operator prescription for `migrateSysNotificationToEvent` — a runner the #16194 retirement (decision batch #88) removed from `@objectstack/metadata/migrations`. An operator following the cut-over list writes an import that does not resolve: a copy-the-example-and-it-fails defect, not a stylistic one. ## ⭐ The discrimination this card is about — two occurrences, ONE defect | occurrence | what it is | disposition | |---|---|---| | `0030` § *Remaining work* → objectui cut-over — "Run `migrateSysNotificationToEvent` during the cut-over…" | a **prescription addressed to someone about to act** | **corrected** | | `0030` § *Shipped (merged to `main`)* → `P0 — Seams` row — "…idempotent `migrateSysNotificationToEvent`. \| #1434" | a **record of what a past release shipped**, true when written | ⛔ **left byte-for-byte as it stands** | **My reading of the file agrees with the card's split, and here is the structural evidence for it rather than a restatement.** The untouched occurrence sits inside the table under the heading `### Shipped (merged to `main`)` — one row per phase, each carrying the PR number that shipped it (`#1434`). The corrected occurrence sits under `### Remaining work (handed off to a follow-up agent)`, in an imperative bullet list of steps a follow-up agent is told to perform. Retro-editing the shipped row would be rewriting history to make a grep pass, and it is the accrete-a-row-per-release pattern the release guardrail exists to stop. `git diff` on this branch contains **zero** hits for `P0 — Seams` — the row is not in the diff at all. ## ⚠️ The widening request (`5611847419`) — **TAKEN**, and declared The `CONTRACT_REVIEW_TIER` verdict on PR #17194 (finding F2) named a second line of the same class in a different ADR. The dispatching seat did **not** rule it in or out of scope and asked for the decision to be made out loud. **It is taken**, and the same test was applied to it first: - `docs/adr/0052-audit-is-not-the-activity-feed.md` § *6. Rollout* → *P0b* read "`sys_notification` **is deferred** — it **is mid-migration** to an event model (`metadata/.../migrate-sys-notification-to-event.ts`, ADR-0030), so moving it now would collide with that in-flight work." - Present tense, a claim about **what the platform does today**, and it names a path that is **deleted from disk**. That puts it on the `:105` side of the test, not the shipped-history side. Both halves of the sentence are false as of the retirement. **Why take it rather than file it.** It is the same defect, from the same retirement, in the same governed tree, and it needs the same sentence written. Leaving it means a second card, a second governed-surface PR and a second hand-merge for one sentence. The PM comment that recorded it declined to file it as a second card for exactly that reason. **What the correction deliberately does NOT do.** It records that the stated collision reason is gone — it does **not** decide whether the `sys_notification` ownership move now proceeds. That disposition is a decision for ADR-0052's own record owner, and the line says so in as many words. ADR-0052's **status line is not amended**: no decision of ADR-0052 moved, only one sentence of rationale was false. ## The one judgement call — ADR-0030's amended status line The card's "Suggested shape" asked for a decision on whether ADR-0030 wants an amended status line naming the retirement. **It does, and the PR writes one** (one line, appended to the existing `**Status**` line). Prime Directive #13: reversing a recorded decision is itself a decision, and it needs a new ADR **or an amended status line on the old one**. The retirement already happened, elsewhere; because `docs/adr/**` is governed, PR #17194 correctly could not carry the amendment, so this PR is where it is owed. Without it, the Status line still reads "**P0–P3b2 shipped**" with no trace that a shipped P0 item was withdrawn, and a reader who greps the status learns nothing. The wording follows the register's own precedents for this exact shape — ADR-0005 (`Amended (2026-08-09, #6825 — the Phase-1 overlay-index migration is deleted…)`), ADR-0127 and ADR-0045 — and closes with an explicit "nothing else moves" so it cannot be read as a wider reversal. ⚠️ **This is the line to strike first** if the seat or the maintainer wants a smaller diff: the `:105` correction stands on its own without it. ## Premise re-verified on this branch's base (`32708262d`) ``` $ git grep -nE 'migrateSysNotificationToEvent' -- . ':!*CHANGELOG.md' ':!content/docs/releases/' .changeset/retire-adr-0030-notification-event-migration.md:21:- `migrateSysNotificationToEvent` (`@objectstack/metadata/migrations`) — deleted. docs/adr/0030-notification-platform-convergence.md:80 (the shipped-history row — untouched) docs/adr/0030-notification-platform-convergence.md:105 (the prescription — this PR) docs/adr/0052-audit-is-not-the-activity-feed.md:327 (via its file path — this PR) docs/handoff/adr-0030-notification-convergence.md:126 (the tombstone, already correct) packages/metadata/src/migrations/index.ts:50 (barrel TOMBSTONE) packages/spec/src/system/migration.zod.ts:175 (retired id docblock) + three retirement pin tests ``` `packages/metadata/src/migrations/` holds no `migrate-sys-notification-to-event.ts`. Every remaining occurrence in shipped code is a tombstone or a pin asserting the absence. ⇒ the premise **holds**: the prescription names a call that no longer exists. ## Local gates — 19 derived, 19 run, 0 NOT MEASURED Derived with `node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands` against the actual changed files, every exit code captured **before** any pipe, reconciled with `--ran` in the `command :: exit code` form the tool asks for: ``` ✓ dispatch-gates --ran: 19 derived famil(ies) accounted for — 19 run, 0 NOT-MEASURED (a DERIVED zero — all 19 recorded an exit code and none of them is 3). ``` All 19 exited **0**, the ADR-specific ones among them: `check-adr-links.mjs` · `check-adr-symbol-anchors.mjs` · `check:adr-anchors` · `check:doc-authoring` · `check:pm-governed-merges` · `check:pm-prior-rulings` · `check:nul-bytes` · `@objectstack/lint check:doc-formula-expressions`. `check:doc-formula-expressions` first exited **3 — PREREQUISITE NOT MET** (`@objectstack/formula` and `@objectstack/lint` unbuilt). That is not a finding and was not recorded as one: the two packages were built and the gate re-run, where it exited 0. **Build / test scope.** The diff touches no package, so the dependency-closure build is empty and no package's `test`/`typecheck` is affected. The build above was a gate prerequisite only. **Repo-wide eslint — a measured narrowing, not a skipped run.** (1) Population, read from eslint's own config: every `files:` block in `eslint.config.mjs` matches only `{ts,tsx,mts,cts,js,jsx,mjs,cjs}`; no block matches Markdown. (2) Count, from `--format json` over both changed files: 2 files, both `File ignored because no matching configuration was supplied`, 0 errors. (3) Non-influence: no block sets `parserOptions.project` or `projectService`, so type-aware linting is not enabled and this diff cannot move the verdict on any untouched file. ## Changeset — `skip-changeset` is warranted, and is NOT applied by this PR The repo has a definite answer and it is the **label**, not an empty changeset: `AGENTS.md` *Post-Task Checklist* §3 scopes `skip-changeset` to "a diff that publishes nothing from any released package", and the empty-changeset route was ruled shut for new files (#5471) — the `Check Changeset` job rejects an empty changeset a PR newly introduces. A docs-only `docs/adr/` diff publishes nothing from any package, so the label is the correct instrument. ⛔ **The dispatching seat's write budget names no label, so this dev did not apply it.** The `Check Changeset` gate will be red until the seat applies `skip-changeset`; that red is the gate working, not a finding. ## Files changed - `docs/adr/0030-notification-platform-convergence.md` — status-line amendment; the cut-over prescription struck and replaced. - `docs/adr/0052-audit-is-not-the-activity-feed.md` — the P0b rollout rationale corrected. Total: 2 files, +16 / −7. ## ⛔ Landing `docs/adr/**` is a governed surface (Prime Directive #14, Tier H). This PR stays **draft** and takes no queue: it lands by the maintainer's hand or on an authorised approval, and no agent seat may flip it ready, enqueue it, arm auto-merge on it, or approve it. --- ## 维护者速读(草稿) > 席位意见一节留空,待席位填写后贴出终稿评论。 ### 改了什么 两个 ADR 文件里的两句话,共 2 个文件、+16 / −7 行,不含任何代码改动。 1. **ADR-0030**(通知平台收敛):「前端切换时运行 `migrateSysNotificationToEvent` 把历史铃铛数据迁过来」这条**操作指令**被划掉,改成记录「该迁移已撤回」,并指向 handoff 文档里已有的墓碑说明;切换步骤从三步变两步。同时在文件顶部的 `Status` 行补了一条 `Amended` 记录,写明这次撤回。 2. **ADR-0052**(审计不是动态流):P0b 那段说 `sys_notification`「正在迁往事件模型(某某文件,ADR-0030)」——这句话的两半现在都是假的(迁移已退役、文件已从磁盘删除)。改成记录「当初因此推迟」+「该理由已不存在」,但**不替记录所有者决定这次搬迁现在要不要做**。 3. ⛔ **ADR-0030 里另一处同名调用(P0 已交付表格第 80 行)一个字没动** —— 它记录的是 #1434 当年确实交付了什么,是历史,不是现状。 ### 为什么改 被点名的那个函数在 #16194(决策批次 #88)里已经从 `@objectstack/metadata/migrations` 删掉了。ADR-0030 那条指令是写给「马上要动手的人」看的:照抄它写出来的 import 解析不了。这属于「照着例子做就失败」,不是措辞问题。 ADR-0052 那句的危害不同但同源:它给一次**推迟**提供理由,而那个理由已经蒸发;后来的人可能继续拿一条死掉的理由往后推。 顶部 `Status` 行那条 `Amended` 是协议第 13 条要求的:推翻一个已记录的决定本身就是决定,必须记在记录上。撤回发生在别处(#16194),而那个 PR 因为受管面规则不能碰 ADR,所以这笔账落在本 PR。 ### 风险与代价(含回滚) - **风险很低**:纯文档散文改动,无代码、无发布面、无生成物。19 个派生门禁全部 exit 0(含 ADR 链接、ADR 锚点、受管面合并审计)。 - **唯一需要您拍板的**:顶部那条 `Amended` 状态行算不算「越界替记录所有者做决定」。本 PR 的判断是「不算 —— 它只是把别处已经做出的裁定记到该记的地方」,但如果您觉得 diff 该更小,**先划掉这一行**,下面 `:105` 的修正独立成立。 - **回滚**:`git revert` 一个 commit 即可,不牵动任何运行时。 ### 席位意见 (留空) ### 你要做的 读完 diff 的 16 行后,**人工合并本 PR**(或给出授权批准)—— ⛔ 它不进合并队列,agent 席位不会翻 ready、不会入队。另外请给它挂上 `skip-changeset` 标签,否则 `Check Changeset` 会一直红(本 PR 不发布任何包,派发席的写预算里没有标签,所以 dev 没有自行挂)。 --- _Generated by [Claude Code](https://claude.ai/code/session_01NcPSwnmJHczmTu6FG7NMjE)_ Co-authored-by: Claude <noreply@anthropic.com>
1 parent be488ce commit 8e368dc

2 files changed

Lines changed: 16 additions & 7 deletions

File tree

‎docs/adr/0030-notification-platform-convergence.md‎

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# ADR-0030 — Notification Platform Convergence (single ingress, layered pipeline)
22

3-
**Status**: Accepted (2026-06-01) — **P0–P3b2 shipped** (P3b-2 digest collapse landed); cross-repo objectui cut-over remains. See [§ Implementation status & remaining work](#implementation-status--remaining-work).
3+
**Status**: Accepted (2026-06-01) — **P0–P3b2 shipped** (P3b-2 digest collapse landed); cross-repo objectui cut-over remains. See [§ Implementation status & remaining work](#implementation-status--remaining-work). · **Amended** (2026-09-20, #16194 — P0's idempotent data migration `migrateSysNotificationToEvent` is **retired**: it had zero production callers and no way to be run, and both ways of giving it one — an `os migrate` sub-command and a boot-time invoker — were refused. Pre-ADR-0030 `sys_notification` rows are therefore **not** carried by the platform on this line. ⛔ Nothing else moves: single ingress, the layered object model and the remaining objectui cut-over read exactly as accepted.)
44
**Supersedes / refines**: [ADR-0012 — Notification Platform](./0012-notification-platform.md) (Draft)
55
**Related**: [ADR-0019 — Approval as a Flow Node](./0019-approval-as-flow-node.md), [ADR-0022 — Connectors vs Messaging Channels](./0022-connectors-vs-messaging-channels.md)
66
**Build spec**: [docs/design/notification-platform-convergence.md](../design/notification-platform-convergence.md)
@@ -102,9 +102,14 @@ configurable daily send-hour (windows flush at local midnight / Monday 00:00).
102102
`(notification_id, user_id, channel)` (the framework has the receipt object +
103103
`delivered` writes, but nothing flips it to `read` yet). Repoint the SDK
104104
`client.notifications.*` helpers to the receipt.
105-
- Run `migrateSysNotificationToEvent` during the cut-over so historical bell rows
106-
carry over. **Sequence:** ship back-end → run migration → flip UI (runbook in the
107-
handoff doc).
105+
- ~~Run `migrateSysNotificationToEvent` during the cut-over so historical bell rows
106+
carry over.~~ **Withdrawn (#16194)** — that runner is retired, so pre-ADR-0030
107+
`sys_notification` rows are **not** carried by the platform on this line: after the
108+
cut-over the bell shows rows emitted from the new pipeline onward, and older
109+
per-user inbox rows stay where they are, unread by the new UI. The reasoning, the
110+
unmeasured-deployment caveat and the reversal path are in the handoff doc's
111+
[Data migration — RETIRED](../handoff/adr-0030-notification-convergence.md#-data-migration--retired-there-is-none)
112+
tombstone. **Sequence:** ship back-end → flip UI (runbook in the handoff doc).
108113

109114
**3. Incremental channels & low-code surface (same `MessagingChannel` seam — each gets retry/outbox for free).**
110115
- **push** (`sys_user_device` + APNs/FCM), **webhook** (reuse the `plugin-webhooks`

‎docs/adr/0052-audit-is-not-the-activity-feed.md‎

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -323,9 +323,13 @@ rather than written twice.
323323
ships P0a.**
324324
- **P0b — ownership, no behavior change.** ✅ `sys_attachment` registration moved
325325
`plugin-audit` → `service-storage` (both always-on, so it stays available; the
326-
definition stays in `platform-objects`). `sys_notification` is **deferred** — it
327-
is mid-migration to an event model (`metadata/.../migrate-sys-notification-to-event.ts`,
328-
ADR-0030), so moving it now would collide with that in-flight work. Still TODO:
326+
definition stays in `platform-objects`). `sys_notification` is **deferred** —
327+
originally because it was mid-migration to an event model (ADR-0030) and moving it
328+
would have collided with that in-flight work. That migration is **retired**
329+
(#16194) and the file this line used to name
330+
(`metadata/.../migrate-sys-notification-to-event.ts`) is deleted, so the collision
331+
reason no longer holds; ⚠️ whether the move now proceeds is a call for this
332+
record's owner, not a consequence of the retirement. Still TODO:
329333
make "collaboration/activity is a platform primitive" an explicit capability
330334
rather than an audit side-effect; keep it default-available so no UI regresses.
331335
- **P1 — kill the split-brain + milestone templates (§5b.2).** Choose the

0 commit comments

Comments
 (0)