Skip to content

Commit 753a14e

Browse files
docs(adr): ADR-0145 amended — a ui-only tombstone's R is judged against the fixed group's @objectstack/spec@M.0.0 cut, and D1 names the ADR-0087 level-half amendment (#27333)
Fixes #27291 Clause-②: no Metadata-protocol: none ## 维护者速读 - **改了什么**:ADR-0145 两处条款各加一条修订注(照 ADR-0087 的修订拼法,原文保留在注里),状态行记为 Accepted(#27251 的合并)并加 Amended 条目。决定本身不变:ui 墓碑随 spec 的窗口退场,退休后一个 major,绝不更长;不删任何墓碑,不改代码、schema 或 changeset。 - **为什么改**:D2 的 ui-only 时钟原来读 `@object-ui/types` 自己的首个 release tag,而该包的 17 从 `17.1.0` 开始、没有 `17.0.0`,于是在 16.1.0 与 17.1.0 之间诞生的 ui-only 墓碑会被读成 R = 17(spec 时钟读 16),比 spec 多活一个 major —— 恰是 D1 禁止的。D1 引的「ADR-0087 2026-09-13 修订」有两段同日文本,现在点名 #18003 的 level-half 那一段。 - **风险与回滚**:只改 ADR 文本,不发布任何包;回滚 = revert 这一个 commit。误差方向:修订前偏长(不会提前删除),修订后与 spec 时钟一致。 - **先看**:`docs/adr/0145-ui-deprecation-tombstones-retire-on-the-spec-window.md` —— ① D2 的 ui-only 条目(新 L87–96,规则本身);② D1 的 level-axis 条目(新 L60–66,仅引文);③ 状态行(新 L3–6)。 - **两分钟验证**:`npm view @object-ui/types versions --json` 看到 `16.1.0` 之后直接是 `17.1.0`;`git ls-remote --tags origin '@objectstack/spec@17.0.0'` 返回一行 —— 修订针对的就是这两个事实。 - **需要你做的**:Tier H(`docs/adr/**`),PR 保持 draft;由 `GOVERNED_APPROVERS` 中的账号批准,或维护者亲手合并 / 入队。 ## What changes One file, `docs/adr/0145-ui-deprecation-tombstones-retire-on-the-spec-window.md`, +17/−7 (167 → 177 lines). Two clauses are amended, each with an in-place `Amended 2026-10-28 (#27291)` note that quotes the former wording; the status entry records the acceptance and the amendment in ADR-0087's spelling. D1's window, D3, D4, D5 and the Applying-the-rule steps are untouched. Nothing is implemented: no tombstone is removed, no code, no schema, no changeset (`skip-changeset`: `docs/adr/**` publishes nothing). **Status line** — before: ```text **Status**: Proposed (2026-10-28). `docs/adr/**` is Tier H (Prime Directive #14): this record becomes **Accepted** by the maintainer's merge. **This record declares; it implements nothing** — … ``` after (PR #27251 merged 2026-10-28T14:43Z; `adr-index` keys the record by its earliest status keyword, so the row reads Accepted): ```text **Status**: Accepted (2026-10-28, #27251) · **Amended** (2026-10-28, #27291 — one clause each; see the amendment notes under D2's ui-only bullet and under D1's level-axis bullet). **This record declares; it implements nothing** — … ``` **D1, level-axis bullet (item 6 of triage's re-review, comment 6471216267 on PR #27251)** — before: ```text (ADR-0087's 2026-09-13 amendment, `scripts/check-changeset-no-major.mjs`) and moves nothing here; ``` after: ```text (ADR-0087's #18003 level-half amendment of 2026-09-13 — the note inside its "Ratified: the pre-launch launch-window exemption" section — and `scripts/check-changeset-no-major.mjs`) and moves nothing here; > **Amended 2026-10-28 (#27291) — the citation names its text.** Was "ADR-0087's 2026-09-13 amendment": ADR-0087 > carries two texts of that date, the #12772 artifact-ingestion addendum being the other, and D1 means the level half. ``` **D2, ui-only bullet (item 5 of the same re-review)** — before: ```text from the ui's own retirement. R is the major of the first `@object-ui/types` release tag (or the first release of the package that publishes the `.d.ts`) whose tree carries the tombstone, on the same convention: first carried by a major's `.0.0` cut counts in the major before it. ``` after: ```text from the ui's own retirement, on the fixed group's clock (D1): R is read off the first `@objectstack/spec` release tag whose tree carries the tombstone's introducing commit (for a commit the ui merge did not import, the first cut after its date — step 2), on the convention the bullets above use: first carried by a major's `.0.0` cut counts in the major before it. ⛔ Never off `@object-ui/types`' own tags: a major's first tag there need not be a `.0.0` cut. > **Amended 2026-10-28 (#27291) — the ui-only clock reads the group's tags.** Was: "R is the major of the first > `@object-ui/types` release tag (or the first release of the package that publishes the `.d.ts`) whose tree carries > the tombstone, on the same convention: first carried by a major's `.0.0` cut counts in the major before it." > `@object-ui/types` opens 17 at `17.1.0` (no `17.0.0`), so that reading gave a tombstone born before the > `@objectstack/spec@17.0.0` cut R = 17 where the spec's clock reads 16: one major longer, which D1 forbids. ``` The clause is one rule, not a two-branch fallback: because the group releases in lockstep (D1), reading the group's `@objectstack/spec` tags gives the same R as the ui package's own tags wherever those coincide, and the spec's R wherever the ui package skipped a `.0.0`. It points at D1 and at Applying-the-rule step 2 (`git tag --contains` on the introducing commit, the pre-merge objectui era dated on a full clone) rather than restating them. **Worked examples (the test the order set; they live here, not in the ADR):** - (a) A ui-only tombstone introduced between `@object-ui/types@16.1.0` and `17.1.0`, before the `@objectstack/spec@17.0.0` cut. Old reading: first `@object-ui/types` tag carrying it is `17.1.0`, not a `.0.0` cut, so R = 17 — carried through 18, due at 19. New reading: the first `@objectstack/spec` tag carrying it is `17.0.0`, a `.0.0` cut, which counts in the major before, so R = 16 — carried through 17, due at the 18 cut, exactly the spec's own answer for a key refused from `17.0.0`. - (b) A tombstone first carried by a 17.x release after the `17.0.0` cut. Both readings: first tag carrying it is `17.x` (x ≥ 1), so R = 17 — carried through 18, due at 19. The amendment moves nothing here. - (c) A tombstone introduced today, after the `18.0.0` cut: first carrying tag `18.x`, R = 18, due at 20 — unchanged. Registry facts the amendment rests on, re-read this run: `npm view @object-ui/types versions --json` lists `… 15.0.0, 16.0.0, 16.1.0, 17.1.0, 17.2.0, 17.3.0, 17.5.0, 17.6.0, 17.7.0, 18.0.0, 18.1.0, 18.2.0` (no `17.0.0`); `git ls-remote --tags origin '@objectstack/spec@17.0.0'` answers `100d9059…`. ## Tests Docs-only diff: no workspace package is touched, so there is no ① dependency closure and no ② package test or typecheck to run; `test:repo` is CI's. The verification is the derived gate set below, all run on head `2d14a9c2`. Dogfood battery: n/a — no `!` in the title and `Clause-②: no`. ## Acceptance notes - **`docs/adr/README.md` (the generated index) is not regenerated here.** `pnpm check:adr-index` is report-only by design and it already warned `stale` on `origin/main` `1c5fe3cb` before this edit: a regen on the clean tree moves ADR-0035's row (amended by #27069 without an index run). On this head a regen would move that row plus the 0145 row and the Accepted/Proposed counts (127/4). Scope here is the one ADR file; the next `pnpm adr:index` run refreshes both rows. Noted, not filed. - PR #27251's `merged_by` reads `os-zhuang` through REST (`merged_at` 2026-10-28T14:43:02Z, merge commit `e9c88f7c`); the status entry records the PR number and date only. - `check:role-word` was not derived for this diff — its roots are `content/docs` and `skills/`, not `docs/adr/` — so the order's gate-list hypothesis overstated the set by that one family; the other named families were all derived. - Two added lines run 121–122 characters; the file already carried a 125-character line (former L5) and no gate reads line length under `docs/adr/`. - The derived gate `pnpm --filter @objectstack/lint run check:doc-formula-expressions` first answered exit 3 `PREREQUISITE NOT MET` (unbuilt `@objectstack/formula` / `@objectstack/lint`) — nothing measured; the two packages were built under `os-verify-lock.sh` (`VERDICT command-exit 0`, held 86s, waited 0s) and the gate rerun exit 0. - Commit trailer pair is the repo's model-free form (`Claude-Session:` + `Co-authored-by: Claude`), per AGENTS.md; no card trailer on the commit. ## Verification Head `2d14a9c2` · derivation `node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack` (no paths; change set from the merge base `1c5fe3cb7`, 1 path, 24 changed lines) → 21 commands, all run in the foreground with exits captured before any pipe. <details> <summary>21 derived gates — every exit 0 (gate 07 after its prerequisite build)</summary> ```text 01 exit=0 node scripts/check-adr-links.mjs ✅ check-adr-links: 929 relative link destination(s) under docs/adr/ resolve 02 exit=0 node scripts/check-adr-links.mjs --self-test 03 exit=0 node scripts/check-closing-keyword-parity.mjs 04 exit=0 node scripts/check-closing-keyword-parity.mjs --self-test 40 assertions, 5 mutations each driven to red 05 exit=0 node scripts/check-comment-mask-corpus.mjs 18830 files, 0 disagree, 0 unparseable 06 exit=0 node scripts/ci/plan-test-core-shards.mjs --self-test 23 case(s) across 5 batteries 07 exit=0 pnpm --filter @objectstack/lint run check:doc-formula-expressions 24 record-scoped formula example(s) across 541 files judged clean (first run: exit 3 PREREQUISITE NOT MET, nothing measured; rerun after build) 08 exit=0 pnpm check:adr-anchors 09 exit=0 pnpm check:adr-index ::warning adr-index: stale (report-only, exit 0 by design; already stale on origin/main) 10 exit=0 pnpm check:adr-symbol-anchors 2787 anchors across 146 records resolve 11 exit=0 pnpm check:ci-filter-parity 12 exit=0 pnpm check:closed-ceremony-text 4911 shipped file(s) read 13 exit=0 pnpm check:cross-package-test-inputs 14 exit=0 pnpm check:doc-authoring sibling-package prose ids hold the baseline 15 exit=0 pnpm check:driver-memory-census 16 exit=0 pnpm check:gitlink-declared 17 exit=0 pnpm check:nul-bytes scanned 22118 text file(s); no raw ASCII control bytes 18 exit=0 pnpm check:pm-governed-merges 19 exit=0 pnpm check:pm-prior-rulings 155 cases pass 20 exit=0 pnpm check:refd-timer-probe 21 exit=0 pnpm check:watch-hint-literal ``` </details> <details> <summary>--ran reconciliation and the prerequisite build</summary> ```text $ node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --ran ran.txt Run reconciliation — 21 derived, 21 run, 0 NOT-MEASURED, 0 UNRUN. ✓ dispatch-gates --ran: 21 derived famil(ies) accounted for — 21 run, 0 NOT-MEASURED (a DERIVED zero — all 21 recorded an exit code and none of them is 3). $ OS_VERIFY_LOCK_SLOT=issue-27291 bash scripts/pm/os-verify-lock.sh -c 'pnpm exec turbo run build --filter=@objectstack/formula --filter=@objectstack/lint --concurrency=2' Tasks: 4 successful, 4 total os-verify-lock: VERDICT command-exit 0 · held the lock 86s (1m26s) · waited 0s ``` </details> Control-character scan of the edited file: `grep -naP '[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]'` — no match. Markdown render check (markdown-it 14.3.3): both amendment notes parse as a `blockquote` inside their list item. CI families this PR owes beyond the local subset (`Lint & Repo Gates`, `Check Documentation Links`, `Governed Surface Queue Guard`, `PR-body guards`, `Check PR Size`) are read from the PR's check-runs, not re-run locally. --- _Generated by [Claude Code](https://claude.ai/code/session_01QSeKYmhU5KEj1nukYhp1Tg)_ --------- Co-authored-by: objectstack-fleet[bot] <noreply@anthropic.com>
1 parent 13f5360 commit 753a14e

2 files changed

Lines changed: 28 additions & 14 deletions

File tree

‎docs/adr/0145-ui-deprecation-tombstones-retire-on-the-spec-window.md‎

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
# ADR-0145: A `?: never` tombstone on the ui authoring face retires on the spec's own window — one major after the retirement it names, never longer
22

3-
**Status**: Proposed (2026-10-28). `docs/adr/**` is Tier H (Prime Directive #14): this record becomes **Accepted** by
4-
the maintainer's merge. **This record declares; it implements nothing** — no tombstone is removed, no code, no schema,
5-
no changeset. The first application batch is its own card, cut after the merge (see [Applying the rule](#applying-the-rule)).
3+
**Status**: Accepted (2026-10-28, #27251) · **Amended** (2026-10-28, #27291 — one clause each; see the amendment notes
4+
under D2's ui-only bullet and under D1's level-axis bullet). **This record declares; it implements nothing** — no
5+
tombstone is removed, no code, no schema, no changeset. The first application batch is its own card, cut after the merge
6+
(see [Applying the rule](#applying-the-rule)).
67
**Decided by**: the maintainer's letter **A** of 2026-10-25T01:46Z on
78
[#25912](https://github.com/objectstack-ai/objectstack/issues/25912) (filed as objectui#13467), transcribed as ruling
89
[`6407810703`](https://github.com/objectstack-ai/objectstack/issues/25912#issuecomment-6407810703) over the seat's
@@ -59,7 +60,10 @@ Spelled on ADR-0087's clock, with **R** the protocol major the retirement belong
5960
- "major" is the major of the one `fixed` release group: `@objectstack/*` and `@object-ui/*` release together, lockstep
6061
with `PROTOCOL_VERSION` at every cut, and the spec's deletion gate reads its `CURRENT_MAJOR` off
6162
`@objectstack/spec`'s package version — so one clock serves both faces. A changeset's *level* is a different axis
62-
(ADR-0087's 2026-09-13 amendment, `scripts/check-changeset-no-major.mjs`) and moves nothing here;
63+
(ADR-0087's #18003 level-half amendment of 2026-09-13 — the note inside its "Ratified: the pre-launch launch-window
64+
exemption" section — and `scripts/check-changeset-no-major.mjs`) and moves nothing here;
65+
> **Amended 2026-10-28 (#27291) — the citation names its text.** Was "ADR-0087's 2026-09-13 amendment": ADR-0087
66+
> carries two texts of that date, the #12772 artifact-ingestion addendum being the other, and D1 means the level half.
6367
- the window binds in both directions: a tombstone that names a spec retirement ⛔ never leaves while the spec still
6468
carries that key's kit (the ui author would lose the remedy the spec still prints), and ⛔ never outlives it — except
6569
as D3 holds it: a named refusal D3 keeps outlives the kit by design (the `agedOutSpecKeyRefusal` twins are that case).
@@ -81,9 +85,16 @@ Spelled on ADR-0087's clock, with **R** the protocol major the retirement belong
8185
window by this record: with the protocol at major 18, any whose R is 16 or below is already due, and the first
8286
application batch takes it.
8387
- **The tombstone names a ui-only retirement** (an objectui or ui card, no spec key behind it): the same window runs
84-
from the ui's own retirement. R is the major of the first `@object-ui/types` release tag (or the first release of the
85-
package that publishes the `.d.ts`) whose tree carries the tombstone, on the same convention: first carried by a
86-
major's `.0.0` cut counts in the major before it.
88+
from the ui's own retirement, on the fixed group's clock (D1): R is read off the first `@objectstack/spec` release tag
89+
whose tree carries the tombstone's introducing commit (for a commit the ui merge did not import, the first
90+
`@objectstack/spec` release cut at or after its date — step 2), on the convention the bullets above use: first carried
91+
by a major's `.0.0` cut counts in the major before it. ⛔ Never off `@object-ui/types`' own tags: a major's first tag
92+
there need not be a `.0.0` cut.
93+
> **Amended 2026-10-28 (#27291) — the ui-only clock reads the group's tags.** Was: "R is the major of the first
94+
> `@object-ui/types` release tag (or the first release of the package that publishes the `.d.ts`) whose tree carries
95+
> the tombstone, on the same convention: first carried by a major's `.0.0` cut counts in the major before it."
96+
> `@object-ui/types` opens 17 at `17.1.0` (no `17.0.0`), so that reading gave a tombstone born before the
97+
> `@objectstack/spec@17.0.0` cut R = 17 where the spec's clock reads 16: one major longer, which D1 forbids.
8798
- **Where R cannot be read** (no tag, no row, a history the reader cannot reach): the tombstone is not due. The batch
8899
reports it as undated, ⛔ never guesses a date — a wrong date removes a remedy early, which is option B by accident.
89100

@@ -140,9 +151,12 @@ what it could not date. ⛔ No count is written here: the population moves, and
140151
2. **Date.** Per member, find the commit that introduced the tombstone with `git log -S'<the member line>' --reverse`
141152
on a **full** clone, then the first release tag that contains it (`git tag --contains`). The ui tree's history before
142153
the ui merge was not imported into this repository: a tombstone older than the merge is dated on a full clone of
143-
`objectstack-ai/objectui`, whose `@object-ui/types@*` tags carry that era. On a shallow clone the reading is refused,
144-
⛔ never read as "no history" (`git rev-parse --is-shallow-repository`, with a control leg of known age). For a
145-
tombstone that names a spec retirement, read R from the spec (D2), not from the ui commit.
154+
`objectstack-ai/objectui`, whose `@object-ui/types@*` tags carry that era — that clone gives the introducing commit
155+
and its date, and R is then read on the group's clock (D2): the first `@objectstack/spec` release cut at or after
156+
that date, a `.0.0` cut counting in the major before it, ⛔ never the `@object-ui/types` tag the clone's
157+
`git tag --contains` names. On a shallow clone the reading is refused, ⛔ never read as "no history"
158+
(`git rev-parse --is-shallow-repository`, with a control leg of known age). For a tombstone that names a spec
159+
retirement, read R from the spec (D2), not from the ui commit.
146160
3. **Judge.** Due ⇔ the current major (D1) ≥ R + 2 and D3 does not hold the key. Report three lists — due, held by
147161
D3 (with the container), undated — and remove only the first.
148162
4. **Remove and re-pin.** Delete the member, its JSDoc and its zod twin together (D3); move any test that pins

‎docs/adr/README.md‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@
1717

1818
| Status | Records |
1919
|---|---|
20-
| Accepted | 126 |
21-
| Proposed | 5 |
20+
| Accepted | 127 |
21+
| Proposed | 4 |
2222
| Superseded | 4 |
2323
| Draft | 3 |
2424
| Deferred | 2 |
@@ -105,7 +105,7 @@ A bare `ADR-0006` names the decision; its current text is [0006-project-environm
105105
| [ADR-0032](./0032-unified-expression-layer.md) | Expression layer for an AI-authored platform — validate-by-default, schema-aware, one CEL language, no silent… | Accepted — implemented; designer builders pending (objectui) (proposed 202… | 2026-06-02 | — | — |
106106
| [ADR-0033](./0033-ai-assisted-metadata-authoring.md) | AI-assisted metadata authoring — one agent brain, draft-gated review, type-agnostic apply, open-core boundary | Accepted — 2026-06-02 | 2026-06-02 | — | cloud ADR-0025 |
107107
| [ADR-0034](./0034-transactional-writes-and-ambient-transaction.md) | Robust multi-write transactions (ambient transaction context) | Accepted — implemented (v8.0.0) (calibrated 2026-06-12) | 2026-06-12 | — | — |
108-
| [ADR-0035](./0035-config-driven-master-detail.md) | Config-driven master-detail (declare on the relationship, forms derive) | Accepted | — | — | — |
108+
| [ADR-0035](./0035-config-driven-master-detail.md) | Config-driven master-detail (declare on the relationship, forms derive) | Accepted — · Amended (2026-10-28, #27069, maintainer rulings on that card:… | 2026-10-28 | — | — |
109109
| [ADR-0036](./0036-app-as-rest-api-and-mcp-server.md) | Every app is a REST API + an MCP server — make it visible and connectable after build | Accepted — framework implemented; cloud surfacing pending (proposed 2026-0… | 2026-06-06 | — | — |
110110
| [ADR-0037](./0037-live-canvas-draft-preview.md) | Live Canvas — draft-overlay live preview while you build | Accepted — 2026-06-10 — all four phases implemented: `previewDrafts` reads… | 2026-06-10 | — | — |
111111
| [ADR-0038](./0038-build-verification-loop.md) | Build Verification Loop — the agent builds, verifies, and corrects itself | Accepted — 2026-10-28 (ruled on objectstack#26553, ADR batch 2; proposed 2… | 2026-10-28 | — | cloud ADR-0025 |
@@ -211,7 +211,7 @@ A bare `ADR-0006` names the decision; its current text is [0006-project-environm
211211
| [ADR-0141](./0141-inter-app-dependency-declared-checked-before-install.md) | An app may depend on another installed app — declared in `manifest.dependencies`, checked once before install… | Proposed — 2026-10-25; first draft 2026-10-24. `docs/adr/` is Tier H (Prim… | 2026-10-25 | — | — |
212212
| [ADR-0142](./0142-ownership-queue-membership-claim-and-assignment-rules.md) | An ownership queue is a platform primitive — a queue entity, membership through the existing recipient kinds,… | Proposed — 2026-10-25 · Amended (2026-10-28, ruling `6457475657` on #25769… | 2026-10-25 | — | — |
213213
| [ADR-0143](./0143-outbound-connector-auth-is-open-tier.md) | Outbound connector auth is open tier — OAuth2 grants, vendor app-credential exchange and request signing in o… | Accepted — 2026-10-28. Proposed 2026-10-27 (#26833, which also landed the… | 2026-10-28 | — | — |
214-
| [ADR-0145](./0145-ui-deprecation-tombstones-retire-on-the-spec-window.md) | A `?: never` tombstone on the ui authoring face retires on the spec's own window — one major after the retire… | Proposed — 2026-10-28. `docs/adr/` is Tier H (Prime Directive #14): this r… | 2026-10-28 | — | — |
214+
| [ADR-0145](./0145-ui-deprecation-tombstones-retire-on-the-spec-window.md) | A `?: never` tombstone on the ui authoring face retires on the spec's own window — one major after the retire… | Accepted — 2026-10-28, #27251 · Amended (2026-10-28, #27291 — one clause e… | 2026-10-28 | — | — |
215215

216216
## ObjectUI registry — `ui/docs/adr/` (`ui-` prefix)
217217

0 commit comments

Comments
 (0)