Repository navigation
Commit daedf1f
docs(adr-0087): D3 carries one semantic entry per retirement family, even when D2 is lossless (#20254)
Fixes #20188
Clause-②: no
## What
Four governed-text sites still taught the D3 rule from before ruling B.
This PR brings all four in line with it. Ruling B says every retirement
family gets exactly one ADR-0087 D3 `semantic` entry, even when a
lossless D2 conversion also exists, and D2 carries the mechanical data
repair only.
1. **`docs/adr/0087-metadata-protocol-upgrade-contract.md`**: two
parentheses change, nothing else.
- D3 paragraph (`:176` on the base): 「**semantic changes** authored for
that major (the residue D2 cannot express losslessly)」 becomes
「**semantic changes** authored for that major (one entry per retirement
family, even when a lossless D2 conversion also exists for it; D2
carries the mechanical data repair only)」.
- Ratified pre-launch exemption (`:383–:384` on the base): 「every such
break must land as a chain step (a `retiredFromLoadPath` conversion when
lossless, a semantic TODO when not) in the same release」 becomes 「every
such break must land as a chain step (a `retiredFromLoadPath` conversion
when lossless, and one D3 semantic entry per retirement family in every
case; D2 carries the mechanical data repair only) in the same release」.
- Each edited line is split in two, so the file grows two lines. No
other line of either paragraph is reflowed. The status line is
unchanged, and the D2-scope sentence at `:152` (「Semantic changes are
excluded. …」) is untouched because it states D2's scope and does not
contradict the ruling.
- The wording copies the two code-side sites already on `main`: the
`packages/spec/src/migrations/registry.ts` header (`:9`) and the
`packages/spec/src/migrations/types.ts` docblock.
2. **`.claude/skills/spec-property-retirement/SKILL.md` §3** (the
registration checklist):
- The ⚠ preamble now counts **three** independent obligations: the
registry entry (read by the gate), the conversion (followed by the
consumer) and the D3 entry (read by the upgrading agent).
- The response-surface item (`:234` on the base) is rewritten as a
checklist item that every retirement owes: 「每个退役家族一条 D3 `semantic`
条目(`SemanticMigration`;按家族,不按键),即使 D2 conversion 无损也欠 —— D2 只承载机械数据修复」.
The item keeps the non-empty `reason` / `acceptanceCriteria` requirement
and points to the one-file-per-entry layout in
`packages/spec/src/migrations/entries/`.
- Response-surface keys with no rewritable source are still covered.
They are now the case where D3 is the **only** route, no longer the only
case that takes a D3 entry. The `EnhancedApiError.fieldErrors` example
stays.
3. **`.claude/skills/spec-property-retirement/SKILL.md` §4** (the
surface list, `:251`): 「Conversion + 链步 + 精确键 `RETIRED_KEYS_BY_MAJOR`
条目(§3)」 becomes 「Conversion + 链步 + 精确键 `RETIRED_KEYS_BY_MAJOR` 条目 +
每家族一条 D3 `semantic` 条目(§3)」.
- It is a same-line edit, so a dev who works from the §4 list alone no
longer skips the D3 entry.
- The line is not a table row, so the ratchet's table-row width pin (326
bytes) does not apply. No line was added.
## Why
- The ruling was recorded on the retirement-family card as a class-one
self-adjudication (comment `5615360777`, restated at `5634031140`).
- Its authority is the maintainer's ruling on #15954, comment
`5559778263`, verbatim 「one ADR-0087 D3 semantic entry **per family** …
its D3 entry says so」.
- The code-side half already landed in PR #20181. Before this PR, the
ADR and the retirement playbook were the last two places that taught the
old rule. A retirement author who followed either one shipped no D3
entry for a family whose D2 conversion was lossless. The spec half of
that cleanup is tracked separately: #20201 remains open.
- The skills seat judged that the playbook **should** state the rule. It
is the one checklist a retirement dev works from, so leaving the rule
out would let the next retirement miss it again.
## Line budget (the skill ratchet has headroom 0 on this file)
| file | before | after | ceiling |
|---|---|---|---|
| `docs/adr/0087-metadata-protocol-upgrade-contract.md` | 960 | 962 |
none (not in the ratchet map) |
| `.claude/skills/spec-property-retirement/SKILL.md` | 337 | 337 | 337
(`check:pm-skill-ratchet`) |
- The playbook's two new lines are paid for by **deleting content** in
the same section, not by re-wrapping.
- The deleted text is the surface-prose item's closing restatement:
「#5898 起这对每个消费者都成立:门 (c) 的 aged-out tombstone
证明曾是最后一个叶匹配者,现在也读同一张精确键表,再没有任何规则从 `surface` 解析归属」.
- Nothing operative is lost. The item already says 「下游不再有任何东西从它解析归属」 one
clause earlier, and the retired-keys item in the same section still says
that gate (c) reads the exact-key table.
- The ceiling is not raised.
## Verification (all at head `75eeabfc`, the final commit)
- The gate list comes from `node scripts/pm/dispatch-gates.mjs --repo
objectstack-ai/objectstack --commands`. No paths were passed: the change
set was derived from merge base `e4621867` and gave 2 paths, +12 / −10.
- Result: **28 commands, every one exit 0.**
- Reconciliation: `dispatch-gates --ran` prints `28 derived famil(ies)
accounted for — 28 run, 0 NOT-MEASURED (a DERIVED zero — all 28 recorded
an exit code and none of them is 3)`.
- `origin/main` was merged into the branch at `75eeabfc`, because the
derivation at `65eae198` flagged a STALE TREE: two inputs it reads had
changed on `main`. The PR's net diff against `main` is still exactly the
two files.
- The merge changed `packages/lint` sources, so `@objectstack/formula`
and `@objectstack/lint` were rebuilt under the verify lock (`VERDICT
command-exit 0`). `check:doc-formula-expressions` was then rerun and
exited 0.
- Verdict lines for the gates this change touches:
- `pnpm check:pm-skill-ratchet`, exit 0:
`.claude/skills/spec-property-retirement/SKILL.md is 337 lines (ceiling
337; headroom 0)` and `widest table row is 326 bytes (pin 326; headroom
0)`
- `node scripts/check-adr-links.mjs`, exit 0: `690 relative link
destination(s) under docs/adr/ resolve`
- `node scripts/check-adr-symbol-anchors.mjs`, exit 0: `2123 anchors
across 140 records resolve`
- `pnpm check:adr-anchors`, exit 0: `OK (54 anchored file(s), every
governing ADR still referenced …)`
- `pnpm check:doc-authoring`, exit 0: `16350 customer-facing string(s)
across 1093 spec sources clean`
- `pnpm check:nul-bytes`, exit 0: `OK (scanned 9715 text file(s) … no
raw ASCII control bytes)`
- Not in the derived total, and so not measured locally: the 11
wide-population families, the 3 families whose argv needs workflow
values, and the 1 CI job scheduled by these paths. CI runs them.
## Changeset
- None, and `skip-changeset` applies. Both paths are in the fast lane
(`docs/adr/**`, `.claude/**`).
- Measured: the root `package.json` is `private: true` with no `files`,
and no workspace package's `files` reaches either path. Nothing here is
published.
## Acceptance notes
- **Playbook §3 retired-keys item** (`:186–:188`) still says to add the
`RETIRED_KEYS_BY_MAJOR` entry 「在
`packages/spec/src/migrations/registry.ts`」.
- That table has since become a generated region. Entries are now one
file each under `packages/spec/src/migrations/entries/retired-keys/`,
and the entries README says to touch no other file.
- `check:migration-registry` catches a hand edit loudly, so this is
drift in the pointer, not a silent trap.
- Not a defect class that gets a card; noted here. Carrier: none.
## 维护者速读(草稿)
**改了什么**:两个受管文件,只改跟这条规则有关的几句。ADR-0087 里有两处还写着旧规则:D3 段说 semantic 条目「只收 D2
无法无损表达的残余」,上线前豁免段说「无损时写 conversion,否则写 semantic
TODO」。两处都改成同一条规则:每个退役家族一条 D3 条目,即使 D2 已能无损转换;D2 只负责机械的数据修复。属性退役手册的 §3
清单和 §4 汇总行也补上了这条义务。
**为什么改**:这条规则已经裁定(B 方案,依据是维护者在 #15954 上的原话「one ADR-0087 D3 semantic
entry per family」)。代码侧的两处注释已经改完,只剩 ADR 和手册还在教旧规则。照着旧文字做退役的人,会在 D2 无损时漏掉
D3 条目,升级方的 agent 就拿不到那一条判断提示。第 18 版已经有两个键因此漏了。
**风险与代价(含回滚)**:只改文字,不动代码、不动任何 schema 或已发布的包,不需要 changeset。ADR
多出两行;手册行数仍守在上限 337 行,新增的两行靠删掉同一节里一句重复的历史说明来抵。回滚就是 revert 这个 PR。
**席位意见**:
**你要做的**:审阅这两段改动,同意就在本 PR 上批准(Approve)。
---
_Generated by [Claude
Code](https://claude.ai/code/session_01MjvgiFAmjHqsxy1XLiVYfH)_
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent d498113 commit daedf1f
2 files changed
Lines changed: 12 additions & 10 deletions
File tree
- .claude/skills/spec-property-retirement
- docs/adr
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
174 | 174 | | |
175 | 175 | | |
176 | 176 | | |
177 | | - | |
178 | | - | |
| 177 | + | |
| 178 | + | |
179 | 179 | | |
180 | 180 | | |
181 | 181 | | |
| |||
203 | 203 | | |
204 | 204 | | |
205 | 205 | | |
206 | | - | |
207 | | - | |
208 | | - | |
| 206 | + | |
209 | 207 | | |
210 | 208 | | |
211 | 209 | | |
| |||
231 | 229 | | |
232 | 230 | | |
233 | 231 | | |
234 | | - | |
235 | | - | |
| 232 | + | |
| 233 | + | |
| 234 | + | |
| 235 | + | |
236 | 236 | | |
237 | 237 | | |
238 | 238 | | |
| |||
248 | 248 | | |
249 | 249 | | |
250 | 250 | | |
251 | | - | |
| 251 | + | |
252 | 252 | | |
253 | 253 | | |
254 | 254 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
173 | 173 | | |
174 | 174 | | |
175 | 175 | | |
176 | | - | |
| 176 | + | |
| 177 | + | |
177 | 178 | | |
178 | 179 | | |
179 | 180 | | |
| |||
381 | 382 | | |
382 | 383 | | |
383 | 384 | | |
384 | | - | |
| 385 | + | |
| 386 | + | |
385 | 387 | | |
386 | 388 | | |
387 | 389 | | |
| |||
0 commit comments