Skip to content

Commit 495c263

Browse files
claude[bot]claude
andauthored
docs(docs-audit): point the anchor-lag prose at the live gate instead of a number (#17795)
Clause-②: no Closes #16200 ## What this changes Two pieces of prose stated the `authorable-surface.base.json` anchor's lag behind the live ratchet as a bare count, with no revision and no date attached, so a reader took each as a statement about the tree in front of them: - `scripts/docs-audit/README.md` — "measured on this tree it lagged the ratchet by 532 keys" - `scripts/docs-audit/affected-docs.mjs`, the `AUTHORABLE_KEY_SUFFIX_RE` docblock — the same sentence, plus "an exact-match lookup would silently drop all 103 of them" Both now name **`check:authorable-surface`** as the thing that prints the current delta on every run. A pointer to a live instrument replaces a number that decays. ## Why not simply write today's number in **A citation of a past measurement** ("measured on 2026-09-02 at `abc1234`: 532") and **a live claim** ("it lags by 532") are two different kinds of sentence with two different repairs. Both carriers were written as the second and read as the first. Re-measuring and writing the fresher figure in would manufacture the second kind all over again — it buys a few days and reproduces the defect. ## The irony, which is itself the argument for this shape PR #16199 landed a warning about a **stale artifact** and deliberately stated **no count**, for exactly this reason: *"No count is stated: the gate prints the current delta on every run, and a hard-coded number in a warning about staleness is the same defect one level up."* The two live counterexamples sat in the very file that PR names as the **reference consumer** for the union read. The convention already existed in this codebase, was chosen deliberately by the adjacent card, and these two sentences predate it. That is the whole case for pointing at the instrument rather than pinning a figure to a rev: the correct form was already here, one directory away, in prose about this exact artifact. ## The argument the sentences support is untouched — and stronger The claim is that the anchor's lag is real, load-bearing and growing. It survives verbatim, stated in the terms that cannot rot: `data/Object:editMode` and every key of `security/OrgScopingEntitlement` and `api/ProvenanceWaiver` are absent from the anchor and present in `authorable-surface/`, and the class grows with every key authored after `baseRev`. Those are the same facts `--self-test` pins behaviourally, against the live artifacts, on every run. ## Re-measurement (historical citations, not new live claims) Measured at `952b9c5e59b7` on **2026-09-12**, by reading the same two artifacts the tool reads and stripping the annotation with the tool's own `AUTHORABLE_KEY_SUFFIX_RE`: | figure | as written | card, `d5d8d50db`, 2026-09-06 | this PR, `952b9c5e59b7`, 2026-09-12 | |:--|--:|--:|--:| | live-ratchet keys absent from the anchor (annotation stripped) | 532 | 604 | **863** | | annotated (`[RETIRED]`-class) keys the ratchet carries | 103 | 206 | **209** | | shard files under `packages/spec/authorable-surface/` | 11 | 14 | **14** | Ten days moved the headline figure by 62%. ⛔ None of these numbers is written into the tree by this PR; they are here as the evidence for removing them. **The instrument was verified, not assumed.** `pnpm --filter @objectstack/spec check:authorable-surface` prints, on this tree: ``` ℹ️ authorable-surface.base.json trails the baseline at 952b9c5: it mirrors the older 53ef057, and they differ by 970 key(s) only that baseline has, 1034 only the anchor has ``` Those two counts reproduce byte-exactly from the raw (unstripped) key sets — `970` live-only, `1034` anchor-only — so the gate really does answer the question the deleted sentences were answering, and it answers it for whatever tree it runs on. ## The third carrier, and why it is in this diff and not a follow-up The `--self-test` battery carried a **verbatim copy** of the same `103` sentence beside the `[RETIRED]` case (`affected-docs.mjs`, the `buildContainerSurface.isAuthorable` tombstone check). Leaving it would have left one carrier in the same file still asserting a figure this PR removes from the docblock twelve hundred lines up — a contradiction created by this change rather than inherited. Mechanical, identical repair, same file, same gate family, no new verification surface. ## 验收备注 ### Reverse-read: other bare numbers of the same kind in `scripts/docs-audit/` The discriminating test used: *does the sentence read as current state, and does the quantity decay with the tree?* A number bound to a named commit, a named card or a dated ruling is a citation of a past measurement and is not this defect. **One finding, and it is outside this card's scope by triage's own boundary:** the README states the hand-written corpus as **178 pages** in five places (lines ~188, ~192, ~493, ~627), unanchored. `check:docs-audit-scope` prints `195 hand-written doc(s)` on this tree. Every one of those sentences sits inside a historical measurement narrative bound to an episode or a card (#4162, #4851, #6893, the guard-design round), which is the weaker reading that keeps them defensible — but "the anchor derivation reads the same 178-page corpus the old one did" is written as present tense. Noted, **not filed**: triage ruled explicitly that a repo-wide hunt for hard-coded counts "is a different card with its own population", and the population card is the PM's to open, not a rider on this one. Successor: the `domain:devx` PM seat. **Zeros, reported as readings rather than as silence:** - **Other `532` / `103` references anywhere in the repo — zero.** `git grep` for `532 keys`, `103 of them`, `lagged the ratchet`, `lagged the live ratchet` over the whole tree returns nothing after this diff, so no sibling file quotes the figures these carriers held. - **Hard-coded shard count (`11`) in `scripts/docs-audit/` — zero.** The card's third figure came from #14612's triage comment, never from a carrier in this directory; there was nothing here to repair. - **`"measured on this tree"` live-claim phrasing inside `scripts/docs-audit/` — two other sites, both sound.** `affected-docs.mjs` line ~1344 ("zero commands declare `static topic`, and the one `static id` (`init.ts` to `'init'`) agrees with its path") was re-verified against `packages/cli/src/commands/` and is **still true** — zero `static topic`, and `init.ts:912` carries `static override id = 'init'`. It is also a claim about a *zero* whose failure direction the docblock names, not a decaying magnitude. Line ~6019 already carries its rev (`f5a7f9c88`, 7 warm runs) and is the correct form. - **Anything this diff falsifies elsewhere in the tree — zero.** No pin, fixture, gate, workflow or doc reads these sentences; the repo-wide grep above is the reading. Two sites outside `scripts/docs-audit/` use the same "measured on this tree" phrasing (`scripts/check-bash32-floor.mjs` ~121, `scripts/pm/dispatch-gates.mjs` ~8307; the second carries a count, "one of the six"). Out of scope here by the same triage boundary; they belong to the population card above. ### Verification All **34** gate families `scripts/pm/dispatch-gates.mjs` derives for this change set were run in this worktree and every one exited `0`; reconciled with `--ran` carrying exit codes: ``` ✓ dispatch-gates --ran: 34 derived famil(ies) accounted for — 34 run, 0 NOT-MEASURED (a DERIVED zero — all 34 recorded an exit code and none of them is 3). ``` The load-bearing ones for this diff, with the verdict lines they printed: - `pnpm check:docs-audit-scope` — `✓ affected-docs self-test: 585 cases pass.` / `✓ check-audit-scope self-test: 32 cases pass.` - `node scripts/docs-audit/check-affected-docs.mjs` — exit `0` (this is the discoverable name for `affected-docs.mjs --self-test`; no `*.test.ts` in the tree names `affected-docs`, so this wrapper is the script's whole suite) - `pnpm --filter @objectstack/spec run check:authorable-surface` — exit `0`, and the source of the delta line quoted above - `pnpm check:nul-bytes` — exit `0`; plus a direct control-character sweep over both edited files, clean Repo-wide `pnpm lint` was **not** run — it is the CI-owned run, and no narrowing is claimed here in its place. No changed file carries executable behaviour. ### Changeset: `skip-changeset` Measured rather than assumed. `scripts/docs-audit/` is repo tooling: the root manifest is `private: true`, and no non-private package's `files[]` names a path that reaches `scripts/` (checked across every `packages/**/package.json`; positive control — `packages/spec`'s `files[]` resolves to real published paths such as `dist`, `json-schema`, `api-surface`, so the zero is a measurement and not an empty scan). Nothing published moves ⇒ the `skip-changeset` **label** is applied to this PR. ### Clause-② `no`. The diff changes explanatory prose in repo tooling only. It touches no spec schema, no published `exports`, no wire shape and no authorable key — nothing a contract review has a surface to review. The card-side carrier the PM placed reads `no`; this PR-body carrier agrees and was self-verified with `readClause2Line()`. ### Governance No governed surface is touched (`docs/adr/**`, `.claude/**`, `skills/**`, `AGENTS.md`, `CLAUDE.md` are all absent from the file list). Left as a **draft** and **not** armed for auto-merge — arming is the PM's act. --- _Generated by [Claude Code](https://claude.ai/code/session_012GKcPZbMoGq7WPzKLfRBTU)_ Co-authored-by: Claude <noreply@anthropic.com>
1 parent 8da7832 commit 495c263

2 files changed

Lines changed: 18 additions & 10 deletions

File tree

‎scripts/docs-audit/README.md‎

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -121,9 +121,12 @@ card, not a local fix.
121121
⚠️ The authorable surface is read as the **union** of `packages/spec/authorable-surface/`
122122
(the live per-category ratchet, read as one set) and
123123
`packages/spec/authorable-surface.base.json` (the artifact #12824 names). The second is an
124-
**anchor**, pinned at a fixed `baseRev` for the deletion gate — measured on this tree it
125-
lagged the ratchet by 532 keys, including `data/Object:editMode` and every key of
126-
`security/OrgScopingEntitlement` and `api/ProvenanceWaiver`. Reading the anchor alone would
124+
**anchor**, pinned at a fixed `baseRev` for the deletion gate, so it is missing every key
125+
authored since — **`check:authorable-surface` prints that lag on every run**, and ⛔ a
126+
count copied into prose here rots (that gate is the live instrument; this sentence is
127+
not). What the lag *is* does not rot, and is what this rule needs: `data/Object:editMode`
128+
and every key of `security/OrgScopingEntitlement` and `api/ProvenanceWaiver` are absent
129+
from the anchor and present in `authorable-surface/`. Reading the anchor alone would
127130
suppress anchors on genuinely authorable keys, and that class grows with every key added
128131
after `baseRev`. A union can only ever keep an anchor one source vouches for, never drop
129132
one more. `[RETIRED]` is stripped for the same reason: a tombstoned key still rejects with

‎scripts/docs-audit/affected-docs.mjs‎

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -466,17 +466,22 @@ const AUTHORABLE_SURFACE_FILE = 'packages/spec/authorable-surface.base.json';
466466
*
467467
* `authorable-surface.base.json` is what #12824 names, and it is an ANCHOR: its own
468468
* `description` says it is "a verbatim copy of the keys in authorable-surface/ as they
469-
* stood at `baseRev`" — a fixed commit for the deletion gate. Measured on this tree it
470-
* lagged the live ratchet by 532 keys, and the lag is load-bearing here: `data/Object:editMode`
471-
* and every key of `security/OrgScopingEntitlement` and `api/ProvenanceWaiver` are absent
472-
* from it and present in `authorable-surface/`, so reading the anchor ALONE would suppress
469+
* stood at `baseRev`" — a fixed commit for the deletion gate, so it is missing every key
470+
* authored since. ⛔ THAT LAG IS NOT STATED HERE AS A NUMBER: `check:authorable-surface`
471+
* prints it on every run, and the anchor's own `description` says so too — a count copied
472+
* into prose about staleness is the same defect one level up, and it rots on the same
473+
* clock as the thing it describes. What does not rot is what the lag IS, which is the
474+
* only part this rule needs: `data/Object:editMode` and every key of
475+
* `security/OrgScopingEntitlement` and `api/ProvenanceWaiver` are absent from the anchor
476+
* and present in `authorable-surface/`, so reading the anchor ALONE would suppress
473477
* anchors on genuinely authorable keys — a false negative, growing with every key added
474-
* after `baseRev`, which is the one direction the ruling forbids.
478+
* after `baseRev`, which is the one direction the ruling forbids. `--self-test` pins that
479+
* class behaviourally, against the live artifacts, and re-measures it on every run.
475480
*
476481
* The union can only ever KEEP an anchor that either source vouches for, never drop one
477482
* more. `[RETIRED]` is stripped for the same reason: the ratchet's own description says a
478483
* tombstoned key "still rejects with an upgrade prescription", so it is still surface a
479-
* page documents, and an exact-match lookup would silently drop all 103 of them.
484+
* page documents, and an exact-match lookup would silently drop every one of them.
480485
*/
481486
const AUTHORABLE_KEY_SUFFIX_RE = /\s\[[A-Z]+\]$/;
482487

@@ -3465,7 +3470,7 @@ function selfTest() {
34653470
false, mergeSurface.isAuthorable('ui/ListView', 'x'));
34663471
// `[RETIRED]` is a TOMBSTONE, not a deletion: the ratchet's own description says such a
34673472
// key "still rejects with an upgrade prescription", so it is still surface a page
3468-
// documents. An exact-match lookup would silently drop all 103 of them.
3473+
// documents. An exact-match lookup would silently drop every one of them.
34693474
const retiredSurface = buildContainerSurface([{ entries: { S: 'ui/PageCardProps' }, collisions: [] }], ['ui/PageCardProps:body [RETIRED]']);
34703475
check('buildContainerSurface.isAuthorable', 'a tombstoned key is still authorable — the annotation is stripped, not matched', 'ui/PageCardProps:body',
34713476
true, retiredSurface.isAuthorable('ui/PageCardProps', 'body'));

0 commit comments

Comments
 (0)