Skip to content

Commit e9c88f7

Browse files
docs(adr): ADR-0145 — ui ?: never tombstones retire on the spec's one-major window (#27251)
<!-- claude-projects-attribution: {"github_login":"os-warren"} --> _Requested by **Warren** · [project thread](https://claude.ai/code/project/chan_01U5RdnAAmkSQmZbqh6FtqZ8?thread=cmsg_01U5RdnAAmkSQmZbqh6FtqZ8JeHddgk25VvfwwsRzoP6xU)_ Fixes #25912 Clause-②: no Metadata-protocol: none ## 维护者速读 - 改了什么:新增一篇 ADR-0145(根 `docs/adr/`)并重生成 ADR 索引:ui 授权面上的 `?: never` 墓碑按 spec 自己的窗口退场,退役后再保留一个 major,到 R+2 major 切出时到期,绝不更长;只立规则,不删任何墓碑、不改代码。 - 为什么改:执行本卡的维护者字母 A(裁决 6407810703);ui 授权面只增不减,每个墓碑都成了永久义务。 - 风险与回滚:只有文档,无发布面;风险在规则措辞本身(容器豁免、R 的读法),回滚即 revert 本 PR。 - 先看:ADR 的 D1(规则)、D2(R 怎么读,含早于 ADR-0087 与只属 ui 的退役)、D3(删墓碑不能把拒绝变成静默接收)。 - 两分钟验证:`pnpm check:adr-index && pnpm check:adr-anchors && node scripts/check-adr-links.mjs`,应全部 exit 0。 - 需要你做的:Tier H,等契约复核 PASS 与席位 ACCEPT 后由您批准合并;在那之前本 PR 保持草稿。 ## What changes - **New record** `docs/adr/0145-ui-deprecation-tombstones-retire-on-the-spec-window.md` (Proposed; becomes Accepted by the maintainer's merge). It records letter A and states: - **D1, the rule.** A `?: never` tombstone leaves the ui authoring face in the first release after the spec major in which its ADR-0087 conversion expires: carried through protocol major R + 1, due from the cut of R + 2, the same cut at which ADR-0087's 2026-10-26 addendum removes the spec's kit. One clock (the protocol major, never the npm major). The window binds both ways: a ui tombstone neither leaves before nor outlives the spec kit for the same key. - **D2, reading R.** Spec-named retirements read R from the spec (`RETIRED_KEYS_BY_MAJOR`, else the release-tag clock the spec's deletion gate uses). A retirement that predates ADR-0087 is counted as if its conversion had run the one-major window from the major it retired in, so no such tombstone gets a fresh window. A ui-only retirement runs the same window from the first `@object-ui/types` release that carried it. Undated means not due, never guessed. - **D3, the container carve-out.** A deletion must leave a refusal: the TS member stays while its container is open (an index signature); the zod twin stays where its container is `.passthrough()` or strips, which is ADR-0087's own strip-container rule and the posture `agedOutSpecKeyRefusal` already takes. Derived faces move together. - **D4, the changeset.** `minor` (never `major`), a **Breaking** note naming each `Type.key` and its remedy, plus the declaration lines and ADR-0087 disposition marker the gates require, not restated. - **Applying the rule.** How the first batch enumerates, dates (`git log -S` on a full clone; pre-merge ui history is in `objectstack-ai/objectui`, not here), judges and re-pins. - **Regenerated index** `docs/adr/README.md` (`pnpm adr:index`). ## Why Ruling 6407810703 (maintainer letter A, 2026-10-25T01:46Z) over seat options 6407810621. Not taken: B (remove when the spec retires the key) and C (no rule). ## Tests None. This PR declares a rule and changes no code, so there is no behaviour to pin or ablate. ## Acceptance notes - **Registry.** The record is in the root `docs/adr/`: #26080 ruling A keeps `ui/docs/adr/` as the frozen ObjectUI import (indexed under `ui-`, files untouched), and `scripts/check-adr-anchors.mjs` resolves only the root registry, so a new ui decision lands here; Prime Directive #13 places an ADR in the repository whose code it governs. No written rule continues new ui decisions in `ui/docs/adr/`. Number 0145: open PR #27239 holds 0144, and no other open PR adds a root record at or above it (the file lists of all 20 open PRs, read through REST before numbering). - **Premise readings** (`origin/main` `9dec0545`, `ui/packages/types/src`, tests excluded): 520 `@deprecated` tags and 675 `?: never` lines (the card read 574 and 640 on 2026-10-24 objectui). The card's "16 `z.never` tombstones" does not hold: the zod tombstones are now spelled through the helpers in `zod/tombstone.zod.ts` (`retirementTombstone`, `agedOutSpecKeyRefusal`, `aliasKeyRefusal`, `handlerKeyRefusal`, `retiredNodeType`), several hundred call sites, so the ADR names the zod twin by what it mirrors rather than by a count. Per ui/AGENTS.md #9 the ADR records no count; the instrument is in "Applying the rule". - **Reading for the contract review.** The ruling's text keys the window to a spec retirement. Most ui tombstones name a ui-only retirement (an objectui card) with no spec key behind them. D2 runs the same window from the ui's own retirement release. This is the narrowest reading consistent with "the window the spec itself runs, never a longer one", and the review should confirm it. - **D3 and the "two faces retire together" facet.** The ruling's facet ① has the zod and `.d.ts` faces retire together. D3 keeps that wherever a deletion leaves a refusal. Where the zod container is `.passthrough()` (everything derived from `BaseSchemaCore`), deleting the twin would make the tolerant face keep the key silently. That is the Prime Directive #12 defect ADR-0087's 2026-10-26 addendum refused for the spec's 58 strip-container tombstones, so the twin stays there until its container closes. - **Not here.** The ui/AGENTS.md #0.1 pointer line rides #25919's AGENTS.md PR, as the ruling's item 3 says. No sweep: the first application batch is its own card after this merge. - **Tier H.** `docs/adr/**` is the register row `adr` (`glob: 'docs/adr/**', tier: GOVERNED_TIER_H` in `scripts/pm/check-governed-merges.mjs`). `dispatch-gates --tier` derives the mandatory ceiling model tier for `docs/adr/**`, with the effort floor at xhigh. This card ran at TIER_DEFAULT under the measured quota exemption the claim records ("ceiling tier unavailable, contract review handed to triage at review time"). Changed lines 160 (+157 / −3) against the 3,000 threshold: under. - **How this PR was opened** (#26617: relay `pr_create` requests the governed approvers on a diff touching a governed path). `11b3e687` adds the record, `98dcc57e` reverts it so the PR opened with an empty net diff and no approver requested, and `01db9123` re-applies it, so the head's tree equals `11b3e687`'s. The seat requests approvers after the contract review PASS and its ACCEPT. ## Verification At `d3e67407` (the head after the contract-review rework; `01db9123` was tree-identical to `11b3e687`), branch point `origin/main` `8d79bbd7`. <details><summary>Gates</summary> - `node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack` at `11b3e687`: 21 commands, each exit captured before any pipe: - `node scripts/check-adr-links.mjs` :: exit 0 - `node scripts/check-adr-links.mjs --self-test` :: exit 0 - `node scripts/check-closing-keyword-parity.mjs` :: exit 0 - `node scripts/check-closing-keyword-parity.mjs --self-test` :: exit 0 - `node scripts/check-comment-mask-corpus.mjs` :: exit 0 - `node scripts/ci/plan-test-core-shards.mjs --self-test` :: exit 0 - `pnpm --filter @objectstack/lint run check:doc-formula-expressions` :: exit 0 - `pnpm check:adr-anchors` :: exit 0 - `pnpm check:adr-index` :: exit 0 - `pnpm check:adr-symbol-anchors` :: exit 0 - `pnpm check:ci-filter-parity` :: exit 0 - `pnpm check:closed-ceremony-text` :: exit 0 - `pnpm check:cross-package-test-inputs` :: exit 0 - `pnpm check:doc-authoring` :: exit 0 - `pnpm check:driver-memory-census` :: exit 0 - `pnpm check:gitlink-declared` :: exit 0 - `pnpm check:nul-bytes` :: exit 0 - `pnpm check:pm-governed-merges` :: exit 0 - `pnpm check:pm-prior-rulings` :: exit 0 - `pnpm check:refd-timer-probe` :: exit 0 - `pnpm check:watch-hint-literal` :: exit 0 - `check:doc-formula-expressions` first exited 3 (prerequisite not met: nothing measured) and exited 0 after `pnpm exec turbo run build --filter=@objectstack/formula --filter=@objectstack/lint` (under the verification lock, exit 0). - `--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)". - `pnpm --dir ui run check:new-line-citations`: "0 new citation(s)", exit 0. - Not run locally, CI's: the type-check lanes and the Plan Test Core shards step `--commands` lists as NOT MEASURED (no TypeScript changes here). </details> --- _Generated by [Claude Code](https://claude.ai/code/session_01JQwxbYznNtcYGX8apHQPtk)_ --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent c59b1bf commit e9c88f7

2 files changed

Lines changed: 171 additions & 3 deletions

File tree

Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
# 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
2+
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)).
6+
**Decided by**: the maintainer's letter **A** of 2026-10-25T01:46Z on
7+
[#25912](https://github.com/objectstack-ai/objectstack/issues/25912) (filed as objectui#13467), transcribed as ruling
8+
[`6407810703`](https://github.com/objectstack-ai/objectstack/issues/25912#issuecomment-6407810703) over the seat's
9+
options [`6407810621`](https://github.com/objectstack-ai/objectstack/issues/25912#issuecomment-6407810621). Executed
10+
here as written and ⛔ not re-opened. Not taken: **B** (a tombstone leaves the day the spec retires its key — the remedy
11+
would die before the authors on the previous major stop needing it) and **C** (no rule — the face only grows).
12+
**Builds on**: [ADR-0087](./0087-metadata-protocol-upgrade-contract.md) (D2's one-major conversion window and its
13+
2026-10-26 addendum, "retirement kits age out after one major" — the window this record reads, ⛔ never restates or
14+
changes), [ADR-0049](./0049-no-unenforced-security-properties.md) (the retirement-tombstone convention the ui mirrors
15+
spell through `retirementTombstone`), AGENTS.md Prime Directive #12 (a deletion that turns a refusal into a silent
16+
accept is the defect it names) and Post-Task Checklist step 3 (the changeset).
17+
**Governs**: every `?: never` member on the ui TypeScript authoring face — `ui/packages/types` and any `.d.ts` another
18+
`ui/packages/*` package publishes — and the zod twin that mirrors it. ⛔ Not a live `@deprecated` member (an alias the
19+
runtime still accepts): it is not a tombstone, and its retirement is its own card's.
20+
**Registry**: the root `docs/adr/`. The ruling's words were "objectui `docs/adr/**`", written before the card moved into
21+
this repository. Here `ui/docs/adr/` is the imported ObjectUI sequence, files untouched and indexed under the `ui-`
22+
prefix (#26080, ruling A), and `scripts/check-adr-anchors.mjs` resolves a bare `ADR-NNNN` against the root registry
23+
only, spelling a ui record `ObjectUI ADR-NNNN`; so a new decision governing `ui/` code lands here (Prime Directive #13:
24+
an ADR lives in the repository whose code it governs).
25+
26+
---
27+
28+
## Context
29+
30+
The ui authoring face refuses a retired key **by name**. `BaseSchema` declares no index signature (ui/AGENTS.md #0.1),
31+
so a fresh node literal refuses any key no declaration names; a retired key is kept declared as `key?: never` with a
32+
`/** @deprecated RETIRED (…) … */` JSDoc whose text is the remedy, and the zod mirror declares the same key through
33+
`retirementTombstone` (or a sibling helper in `zod/tombstone.zod.ts`), so a document that arrives as data is refused at
34+
the key's own path with the same remedy. That is #0.1 working as designed.
35+
36+
What was missing is the exit. Nothing said when a tombstone leaves, so every retirement became a permanent member of
37+
the published `.d.ts`: an AI author reading the face sees the refused keys beside the live ones, and the longer that
38+
list, the more the face teaches what not to write instead of what to write.
39+
40+
The spec already answers the same question for its own face. ADR-0087 D2 applies each conversion for one major, and
41+
its 2026-10-26 addendum carries the retirement kit — the `retiredKey()` tombstone with its conversion — through the
42+
protocol major after the one it retired in, removing it when the next major is cut; after that the spec's strict
43+
container refuses the key as an unknown one and the prescription lives in the protocol upgrade guide, the CHANGELOG
44+
and git. The same addendum keeps a tombstone whose container **strips** unknown keys, because deleting it would turn a
45+
refusal into a silent strip. The ui tombstone mirrors the spec's; this record reads that window on the ui face.
46+
47+
## Decision
48+
49+
### D1 — The rule
50+
51+
A `?: never` tombstone leaves the ui authoring face in the first release that follows the spec major in which the
52+
retirement it names has its ADR-0087 conversion expire: **one major after the retirement**, the window the spec itself
53+
runs, ⛔ never a longer one. Its remedy JSDoc ships for exactly that window.
54+
55+
Spelled on ADR-0087's clock, with **R** the protocol major the retirement belongs to (D2 says how R is read):
56+
57+
- the tombstone is carried through major **R + 1**, and is **due** from the cut of major **R + 2** — the same cut at
58+
which the spec's kit for a key retired in R leaves (ADR-0087, 2026-10-26 addendum);
59+
- "major" is the major of the one `fixed` release group: `@objectstack/*` and `@object-ui/*` release together, lockstep
60+
with `PROTOCOL_VERSION` at every cut, and the spec's deletion gate reads its `CURRENT_MAJOR` off
61+
`@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+
- the window binds in both directions: a tombstone that names a spec retirement ⛔ never leaves while the spec still
64+
carries that key's kit (the ui author would lose the remedy the spec still prints), and ⛔ never outlives it — except
65+
as D3 holds it: a named refusal D3 keeps outlives the kit by design (the `agedOutSpecKeyRefusal` twins are that case).
66+
67+
### D2 — Reading R, including a retirement that predates ADR-0087
68+
69+
- **The tombstone names a spec retirement** (its JSDoc or zod guidance names the `@objectstack/spec` key or release it
70+
mirrors): R is the spec major that retired the key — the `RETIRED_KEYS_BY_MAJOR` row where one exists, otherwise the
71+
release-tag clock ADR-0087's deletion gate uses (a key already `[RETIRED]` on the authorable surface at
72+
`@objectstack/spec@<M>.0.0` retired in a major below M). ⚠️ A ui guidance that says a key "was retired in
73+
@objectstack/spec 17.0.0" (`agedOutSpecKeyRefusal`'s `retiredIn`) names the first release that **refused** it; by the
74+
gate's clock that key was already `[RETIRED]` at `17.0.0`, so R is 16, not 17. Reading the guidance's number as R
75+
runs a window one major longer than the spec's, which D1 forbids.
76+
- **The spec retirement predates ADR-0087**, so no conversion was ever registered for it — the pre-launch one-step
77+
breaks of majors 12–15 that ADR-0087's "Ratified: the pre-launch launch-window exemption" section records, or a
78+
retirement older than D2 itself: it is counted **as if its conversion had run the one-major window from the major it
79+
retired in**. R is read on the same tag clock: the major of the first spec release that refused the key, where a key
80+
first refused by a major's `.0.0` cut counts in the major before it. No such tombstone is granted a fresh
81+
window by this record: with the protocol at major 18, any whose R is 16 or below is already due, and the first
82+
application batch takes it.
83+
- **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.
87+
- **Where R cannot be read** (no tag, no row, a history the reader cannot reach): the tombstone is not due. The batch
88+
reports it as undated, ⛔ never guesses a date — a wrong date removes a remedy early, which is option B by accident.
89+
90+
### D3 — A deletion must leave a refusal: the container carve-out
91+
92+
The rule removes a **prescription**, never a **refusal**. ADR-0087's addendum keeps a spec tombstone whose container
93+
strips unknown keys; the same test applies on both ui faces, judged per key:
94+
95+
- **TS face.** The `?: never` member leaves only where its container still refuses the key once it is gone — a type
96+
that declares no index signature, directly or through what it extends or intersects. Where the container is open, the
97+
member stays until the container is closed; closing it is its own card.
98+
- **Zod face.** The zod twin leaves in the same release only where every zod face that judges authored metadata still
99+
refuses the key once it is gone. `BaseSchemaCore` ends `.passthrough()`, so a member deleted from a container derived
100+
from it is **kept in silence** by the tolerant face (the case `agedOutSpecKeyRefusal` in `zod/tombstone.zod.ts`
101+
exists for: the ui keeps its own named refusal once the spec's tombstone ages out). Such a twin stays, as the ui's
102+
refusal, until its container refuses unknown keys — the posture the spec's strip-container tombstones keep.
103+
- **A mirror pair moves together — the key is held, not one face.** Where the TS type and its zod schema are a
104+
registered mirror pair (`ui/packages/types/src/__tests__/zod-mirror-parity.test.ts`), or the TS member is derived from
105+
the zod twin (`z.input` / `z.infer`), the two faces leave together or neither does: a zod container that would keep
106+
the key in silence holds the TS member too, and an open TS container holds the zod twin. That test's fourth
107+
direction, `MirroredUndeclaredKeys` (a key the zod side mirrors and the TS side does not declare), is the pin that
108+
turns a one-sided deletion red — ⛔ never grow its ledger to land one.
109+
110+
A tombstone held by D3 is listed by the batch with the container that holds it; it is not due, and it is not a
111+
defect of this rule.
112+
113+
### D4 — The changeset that drops a tombstone
114+
115+
- Level **`minor`**, ⛔ never `major` (`scripts/check-changeset-no-major.mjs` is the authority), on every package whose
116+
published face loses the member.
117+
- A **Breaking** note naming each removed key as `Type.key` and its remedy — the text of the JSDoc being deleted,
118+
carried over as the FROM → TO line — because from that release on the CHANGELOG is where an author who still writes
119+
the key finds what to write instead.
120+
- The declaration lines and the ADR-0087 disposition marker the changeset gates require (AGENTS.md Post-Task Checklist
121+
step 3); ⛔ their vocabulary is not restated here — the gates print it when they fail.
122+
123+
### D5 — Not in this record
124+
125+
- **No sweep.** This record removes nothing; the first application batch is its own card.
126+
- **The AGENTS.md pointer.** The ruling puts a one-line pointer to this record in ui/AGENTS.md #0.1 on the AGENTS.md
127+
pull request of [#25919](https://github.com/objectstack-ai/objectstack/issues/25919), not here.
128+
- **No new gate.** The spec's deletion gate dates its own `[RETIRED]` lines; whether the ui face gets a twin of that
129+
clock is a later card's question, decided by measurement, ⛔ not by this record.
130+
131+
## Applying the rule
132+
133+
The first application batch — one card per major thereafter — finds due tombstones mechanically and reports
134+
what it could not date. ⛔ No count is written here: the population moves, and the instrument is the reading
135+
(ui/AGENTS.md #9).
136+
137+
1. **Enumerate.** Every `?: never` member under `ui/packages/*/src`, tests excluded
138+
(`git grep -nE '\?: never' -- 'ui/packages/*/src/**' ':!**/__tests__/**' ':!**/*.test.ts' ':!**/*.test.tsx'`), and,
139+
per member, its zod twin on the mirrored schema, whatever helper of `zod/tombstone.zod.ts` spells it.
140+
2. **Date.** Per member, find the commit that introduced the tombstone with `git log -S'<the member line>' --reverse`
141+
on a **full** clone, then the first release tag that contains it (`git tag --contains`). The ui tree's history before
142+
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.
146+
3. **Judge.** Due ⇔ the current major (D1) ≥ R + 2 and D3 does not hold the key. Report three lists — due, held by
147+
D3 (with the container), undated — and remove only the first.
148+
4. **Remove and re-pin.** Delete the member, its JSDoc and its zod twin together (D3); move any test that pins
149+
the tombstone's named refusal to assert what the key meets now — the TS excess-property refusal and the strict zod
150+
face's unknown-key refusal — ⛔ never delete such a pin without its replacement. Ship the D4 changeset.
151+
152+
## Consequences
153+
154+
- The ui authoring face stops only growing: each major sheds the tombstones whose window closed, in step with the
155+
spec's own face, and the two faces never disagree about how long a remedy is printed.
156+
- An author who writes a key after its window meets a bare unknown-key refusal on the TS face, without a remedy; the
157+
remedy lives in the CHANGELOG entry the D4 Breaking note writes. That is the trade ADR-0087 already made for the spec.
158+
- D3 keeps some tombstones past their window, by design: a named refusal outranks a shorter face. Each one held is a
159+
pointer at a container that is still open.
160+
161+
## Alternatives considered
162+
163+
- **B — leave immediately when the spec retires the key.** Rejected by the ruling: the remedy disappears while authors
164+
on the previous major still need it.
165+
- **C — no rule.** Rejected by the ruling: every retirement is a permanent obligation on the published face.
166+
- **A longer ui window than the spec's.** Excluded by the ruling's "never a longer one": the faces would print a remedy
167+
for a key the spec no longer prescribes.

‎docs/adr/README.md‎

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,20 +13,20 @@
1313

1414
## Summary
1515

16-
144 records under `docs/adr/` (139 numbers), 11 under `ui/docs/adr/` (listed separately below).
16+
145 records under `docs/adr/` (140 numbers), 11 under `ui/docs/adr/` (listed separately below).
1717

1818
| Status | Records |
1919
|---|---|
2020
| Accepted | 126 |
21-
| Proposed | 4 |
21+
| Proposed | 5 |
2222
| Superseded | 4 |
2323
| Draft | 3 |
2424
| Deferred | 2 |
2525
| Withdrawn | 2 |
2626
| Amended | 1 |
2727
| Partially implemented | 1 |
2828
| Revised | 1 |
29-
| **Total** | **144** |
29+
| **Total** | **145** |
3030

3131
## Shared numbers
3232

@@ -211,6 +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 | — | — |
214215

215216
## ObjectUI registry — `ui/docs/adr/` (`ui-` prefix)
216217

0 commit comments

Comments
 (0)