Repository navigation
Commit 47a9002
docs(spec): reconcile the RETIRED_KEYS_BY_MAJOR Lifecycle docblock with check (b3) (#18967)
Part of #18624 — item ① only; the card stays open for the half named
below.
Clause-②: no
`RETIRED_KEYS_BY_MAJOR`'s docblock is shipped text: it reaches consumers
in `@objectstack/spec`'s `dist/index.d.ts`, measured by grepping the
built `.d.ts` for a phrase from this very paragraph against a positive
control. Since check (b3) landed, two of its sentences were false, and
one of them contradicted a remedy the gate prints.
## What was false
| docblock said | check (b3) does |
|:---|:---|
| 「The one state the gate rejects is an entry naming a key that is still
LIVE」 | rejects a **second** state — a NESTED row whose def this build
emits but whose dotted path it does not |
| 「Entries are permanent」 | its refusal text ends `… or delete the entry
from packages/spec/src/migrations/registry.ts` |
| 「its entry here stays, and then names a key the build no longer emits
— the expected steady state, not an error」 | true only for a TOP-LEVEL
key; a nested row never reaches `authorable-surface/` at all, so it has
no aging clock and can never be in that steady state |
An author following the docblock would not delete the row; an author
following the gate would. Both texts ship in the same repository, so two
people each doing as they were told go opposite ways.
## What changed
One file, `packages/spec/src/migrations/registry.ts`, comment text only
— the hand-written docblock above the declaration, outside the
`os-generated` regions (`check:migration-registry` green confirms
nothing generated moved).
- The `## Lifecycle` paragraph scopes the aging-out steady state to a
**top-level** tombstone and says why a nested row can never be in it.
- It lists **both** rejected states with the check that owns each and
the remedy that check actually prints: still-LIVE is check (b2),
nested-and-unresolvable is check (b3).
- It states the routing rule that decides which check judges a row — a
row is read as a path only when its `name` half carries a dot **and**
this build emits no top-level property of that exact name, so a live
dotted top-level key such as the OData context key stays on the map
check (b2) has always judged it on. That mirrors `build-schemas.ts`'s
`!currentKeys.has(k) && isNestedAuthorableKey(k)` routing rather than
paraphrasing it as "has a dot".
- It reconciles permanence with deletion instead of leaving the two to
contradict: a row that was ever TRUE of some build is history and is
never deleted; a row check (b2) or (b3) refuses was never true of any
build, so deleting it removes a false claim rather than a record.
- It repeats check (b3)'s own ⛔ — that check cannot yet tell a wrong row
apart from every truthful one, and for the shapes its refusal enumerates
the remedy is to teach the check, never to delete a row that is telling
the truth.
- The `## What reads it` bullet for check (b) and the `@see` roster name
check (b3), which reads this table and was named by neither.
⛔ No gate behaviour moves. No schema, export, registry entry or refusal
condition is touched; the set of metadata that validates is
byte-for-byte what it was. The changeset is a `patch` because the
shipped `.d.ts` text moves, not because anything executes differently.
## Sweep — the other carriers of the same sentences
Checked before editing, since fixing one carrier and leaving three is
the failure mode this card is an instance of:
- `RETIRED_DEFS_BY_MAJOR`'s parallel `## Lifecycle` paragraph in the
same file carries nearly identical wording. It is **still true** and is
deliberately untouched: check (b3) judges nested KEYS, and that table's
only consumer remains the manifest deletion gate.
- `packages/spec/scripts/lib/nested-authorable-keys.ts` already states
the three-state distinction correctly and at length; nothing there is
stale.
- `packages/spec/src/migrations/entries/README.md` describes the
entry-file layout only and makes no lifecycle claim.
- No test, generated doc or `content/docs/` page quotes the paragraph:
the phrases 「Entries are permanent」 and 「The one state the gate rejects」
occur in this file and nowhere else in the tree.
## What is deliberately NOT in this PR
The card carries three items; this delivers item ① and no more, which is
why the first line reads Part of rather than binding a closing keyword
to the card.
- **Item ②** — check (b3)'s refusal enumerates two legitimate shapes it
cannot tell apart from a wrong row, and a third exists (an ancestor of a
registered nested key tombstoned in place, removed via the guidance
route, or reached through a `$ref` to a tombstoned `$def`). Re-measured
here and structurally real: a tombstoned ancestor node renders as `{
"not": {} }`, which carries no `properties`, so any registered
descendant path under it lands in the same `unresolvable` state. It is
unreached on this tree. Its carrier is the refusal text in
`packages/spec/scripts/build-schemas.ts`, **outside this PR's declared
file surface** (`packages/spec/src/migrations/**` plus any sibling test
pinning the wording), and writing a new enumerated shape is authored
prose rather than a mechanical repair — so it is reported rather than
taken here.
- **Item ③** — re-measured first-hand and confirmed:
`packages/spec/scripts/lib/nested-authorable-keys.ts` contains `items` 4
times and `prefixItems` 0 times, so a tuple-shaped nested row would not
be seen. The card records this as a limit of sight rather than a defect
and asks for no action.
## Verification
All readings taken in a dedicated worktree at head `f75798a2`, after
merging `origin/main`.
- `pnpm --filter @objectstack/spec build` — exit 0; 34/34 declaration
files present.
- `pnpm --filter @objectstack/spec check:generated` — exit 0; **all 15**
generated artifacts up to date, `check:migration-registry` among them.
- `pnpm --filter @objectstack/spec typecheck` — exit 0 (includes
`check:scripts-typecheck` and `check:test-typecheck`).
- `pnpm --filter @objectstack/spec test` — exit 0; **488 test files,
14182 tests passed**.
- `pnpm lint` (the repo-wide union, `eslint . --no-inline-config`) —
exit 0, re-run on this exact head after the merge, 71s.
- Gate families derived mechanically from the change set with `node
scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack`,
re-derived after the changeset existed and again after the merge, then
reconciled with `--ran`: **78 derived, 75 run green, 3 NOT MEASURED, 0
UNRUN.**
Every exit code was captured before any pipe. The three NOT MEASURED are
all `exit 3` = PREREQUISITE NOT MET, which is neither a pass nor a
failure:
- `pnpm check:dual-build-cjs-loads` — needs a whole-repo `pnpm build`
(87 packages have no `dist/`).
- `pnpm check:lean-entry-closure` — needs `@objectstack/objectql` built.
- `node scripts/check-plugin-teardown-shape.mjs --self-test` — its
positive-control fixture is pinned to a commit this shallow checkout
cannot reach; the gate's non-self-test run was green. This one grades
the checker's fixtures, not this diff.
CI covers all three. No reverse-verification or ablation run is reported
because none is owed: this diff adds no gate, changes no cross-package
type, and has no behaviour whose removal could turn a test red.
## Acceptance notes
- `.claude/skills/spec-property-retirement/SKILL.md` §3 warns a
retirement author only about check (b2) ("⚠ **不要**在墓碑落地前先加条目") and never
mentions check (b3). That is **incomplete, not false** — no sentence
there is contradicted — so by the filing rule it is noted rather than
filed. Carrier: a governed surface, outside this card's file surface.
Whoever picks up item ② is the natural taker, since that is the next
edit to touch (b3)'s author-facing text.
---
_Generated by [Claude
Code](https://claude.ai/code/session_01AmH9bKvGoLjiY86Q4Z3og2)_
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent 26c73fb commit 47a9002
2 files changed
Lines changed: 59 additions & 9 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
12140 | 12140 | | |
12141 | 12141 | | |
12142 | 12142 | | |
12143 | | - | |
12144 | | - | |
| 12143 | + | |
| 12144 | + | |
| 12145 | + | |
| 12146 | + | |
| 12147 | + | |
| 12148 | + | |
12145 | 12149 | | |
12146 | 12150 | | |
12147 | 12151 | | |
| |||
12206 | 12210 | | |
12207 | 12211 | | |
12208 | 12212 | | |
12209 | | - | |
12210 | | - | |
12211 | | - | |
12212 | | - | |
12213 | | - | |
12214 | | - | |
| 12213 | + | |
| 12214 | + | |
| 12215 | + | |
| 12216 | + | |
| 12217 | + | |
| 12218 | + | |
12215 | 12219 | | |
12216 | | - | |
| 12220 | + | |
| 12221 | + | |
| 12222 | + | |
| 12223 | + | |
| 12224 | + | |
| 12225 | + | |
| 12226 | + | |
| 12227 | + | |
| 12228 | + | |
| 12229 | + | |
| 12230 | + | |
| 12231 | + | |
| 12232 | + | |
| 12233 | + | |
| 12234 | + | |
| 12235 | + | |
| 12236 | + | |
| 12237 | + | |
| 12238 | + | |
| 12239 | + | |
| 12240 | + | |
| 12241 | + | |
| 12242 | + | |
| 12243 | + | |
| 12244 | + | |
| 12245 | + | |
12217 | 12246 | | |
12218 | 12247 | | |
12219 | 12248 | | |
| |||
0 commit comments