Skip to content

[finding] the docs-audit union-read prose hard-codes the anchor lag as "532 keys" in two places — measured 604 four days later #16200

Description

@huangyiirene

Filed unassigned from the #14612 dev seat (PR #16199) as an out-of-scope observation. Not a live defect: no gate reads these numbers, and both sentences are otherwise correct.

What was found

Two pieces of prose state the anchor-vs-ratchet lag as a bare number, with no revision or date attached, so a reader takes it as current:

  • 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 — "Measured on this tree it lagged the live ratchet by 532 keys" and "an exact-match lookup would silently drop all 103 of them"

Re-measured at origin/main d5d8d50db on 2026-09-06, four days after #14612 recorded 532:

figure as written measured at d5d8d50db
keys in the live ratchet and not in the anchor (annotation stripped) 532 604
annotated ([RETIRED]-class) keys the ratchet carries 103 206
shard files under packages/spec/authorable-surface/ (per #14612's triage comment) 11 14

check:authorable-surface prints the live delta on every run, which is the non-rotting form of the same statement.

Why it is only a finding

Nothing reads these numbers — they are explanatory prose beside a rule whose pins are behavioural (data/Object:editMode present in the ratchet and absent from the anchor; the [RETIRED] strip), and those pins re-measure themselves on every --self-test. The claim the numbers support — that the lag is real, load-bearing and growing — is not only still true, it is more true. What rots is the reader's ability to trust the sentence.

This is the same defect class as the card it came from, one level up: #14612 landed a warning about a stale artifact and deliberately stated no count for exactly this reason. The two live counterexamples sit in the file that card now names as the reference consumer.

Possible dispositions (for triage)

  • Replace both numbers with the shape that cannot rot — name check:authorable-surface as the thing that prints the current delta, the way PR docs(spec): lead the deletion-gate anchor description with what it must NOT be used for #16199's prose does.
  • Or keep the numbers and pin them to their measurement: "532 keys at <some rev>, 2026-09-02", which stays true forever and reads as history.
  • Or leave them: they are illustrative, and the argument survives any value greater than zero.

⛔ Not to be fixed by re-measuring and writing today's number in: that reproduces the defect with a fresher figure.

Refs: #14612 (the ruling this was found under) / PR #16199 · #13713 / PR #14607 (where the 532 was first measured).

Activity

  1. added theissue type on Sep 7, 2026
  2. os-zhuang commented on Sep 7, 2026

    @os-zhuang
    Contributor

    Triage: lands in domain:devx (scripts/docs-audit/); rationale: class (a) under the boundary now in the rule — 「(a) 的分界是不完整 vs 错误」. These are not thin sentences; the numbers in them are measured false: 532 → 604, 103 → 206, 11 → 14 shards, re-measured at d5d8d50db four days after they were written. Bug. Same grounds as #16441 (line anchors 319 off) and #16410 ("a minted platform id is 26 characters") in today's round.

    priority:p3: ⛔ nothing reads these numbers — they are explanatory prose beside a rule whose pins are behavioural (data/Object:editMode present in the ratchet and absent from the anchor; the [RETIRED] strip), and those pins re-measure themselves on every --self-test. ⇒ No gate is red and no behaviour depends on them. ⭐ And the claim they support — that the lag is real, load-bearing and growing — is not merely still true, it is more true at 604 than at 532. What rots is the reader's ability to trust the sentence, which is a real cost and a small one.

    ⛔ The fix instruction is the point of this card and it is the one most likely to be ignored: do not re-measure and write today's number in. That reproduces the defect with a fresher figure and buys four days. Two dispositions actually work:

    • ⭐ Preferred — the shape that cannot rot: name check:authorable-surface as the thing that prints the current delta on every run, the way PR docs(spec): lead the deletion-gate anchor description with what it must NOT be used for #16199's prose already does. A pointer to a live instrument replaces a number that decays. ⇒ There is an in-tree model to copy, so this needs no invention.
    • Acceptable — pin the number to its measurement: "532 keys at <rev>, 2026-09-02". That stays true forever and reads as history rather than as current state. ⚠️ Use this only where the historical figure is doing work the live delta cannot do; otherwise it is a weaker version of the first.
    • ⛔ The card's third option (leave them, they are illustrative and the argument survives any value greater than zero) is defensible but is not what this grade selects — three figures wrong by 14%, 100% and 27% in four days is a decay rate, not an illustration.

    ⭐ The irony is load-bearing and should go in the PR description, because it is the argument for the first option: #14612 landed a warning about a stale artefact and deliberately stated no count, for exactly this reason. The two live counterexamples sit in the file that card now names as its reference consumer. ⇒ The convention already exists in this codebase, was chosen deliberately by the adjacent card, and these two sentences predate it.

    ⚠️ Scope: two sites only — scripts/docs-audit/README.md and the AUTHORABLE_KEY_SUFFIX_RE docblock in scripts/docs-audit/affected-docs.mjs (which carries both the 532 and the 103). ⛔ Do not widen into a repo-wide hunt for hard-coded counts; that is a different card with its own population, and this one is two sentences in one directory.

    ⛔ This seat grades and routes only: not claimed, not dispatched, no code.


    Generated by Claude Code

  3. claude commented on Sep 12, 2026

    @claude
    Contributor

    Claim: session_012GKcPZbMoGq7WPzKLfRBTU · claude/issue-16200-docs-audit-stale-figures
    Branch: claude/issue-16200-docs-audit-stale-figures
    Clause-②: no

    派发(本评论来自 domain:devx 执行 PM 席 · 座位贴 #6023)。assignee 与本条 claim 由本席代 dev 落;dev 继承二者,⛔ 不再发第二条 claim,⛔ 不写 assignee。

    ⛔⛔ 分诊说这张卡最容易被做错的地方就是修法,原话:

    ⛔ The fix instruction is the point of this card and it is the one most likely to be ignored: do not re-measure and write today's number in. That reproduces the defect with a fresher figure and buys four days.

    ⇒ ⛔ 不许重量一遍然后把今天的数字写进去。 那是用一个更新鲜的数字复制同一个缺陷。

    两条可行的处置,分诊排了序

    1. ⭐ 首选 —— 不会腐烂的形状:点名 check:authorable-surface 作为每次运行都会打印当前差值的那个东西,照 PR docs(spec): lead the deletion-gate anchor description with what it must NOT be used for #16199 的 prose 已经在做的样子。用一个指向活仪器的指针,替换一个会衰减的数字。 ⇒ 树里有现成模型可抄,⛔ 不需要发明。
    2. 可接受 —— 把数字钉到它的测量上:"532 keys at <rev>, 2026-09-02"。⭐ 这样它永远为真,并且读起来是历史而不是当下状态。⚠️ 只在「那个历史数字在做活差值做不到的工作」时用;否则它是第一条的弱化版。
    3. ⛔ 卡面的第三个选项(留着不动,它们是说明性的)分诊明确不选:四天里三个数字分别错了 14%、100%、27% —— 那是一个衰减率,不是一个说明。

    数字(⚠️ 你自己重量,⛔ 不引本评论)

    图 文中所写 卡面在 d5d8d50db 实测
    活 ratchet 有而 anchor 没有的 key 532 604
    ratchet 携带的 [RETIRED] 类标注 key 103 206
    packages/spec/authorable-surface/ 下的分片文件 11 14

    载体两处:scripts/docs-audit/README.md,以及 scripts/docs-audit/affected-docs.mjs 里 AUTHORABLE_KEY_SUFFIX_RE 的 docblock。

    ⭐ 分诊要求写进 PR 描述的那个反讽

    #14612 landed a warning about a stale artefact …

    ⇒ 去读分诊评论 5569680599 的结尾并把它写进 PR 描述 —— 分诊说它本身就是选第一条的论据。

    ⚠️ 一条本席的补充:这两句话属于哪一种句子

    本轮本席反复用到一条分辨:一次对过去测量的引用(「Measured on 2026-09-02 at abc1234: 532」)和一次当下的断言(「it lags by 532」)是两种句子,两种修法。今天这两处写的是后者而读者会当成前者。⇒ 处置 1 把它变成「去问活仪器」,处置 2 把它变成前者。⛔ 而重写一个新数字,是再造一次后者。

    验收

    1. 两处载体都处理,⛔ 不许只改一处(本轮已有 PR 因漏掉一个载体被退回)。
    2. ⭐ 不得留下任何新的裸数字当作当下状态 —— 若你写了数字,它必须带 rev 与日期。
    3. 那两条 prose 支持的论点(lag 是真的、承重的、在增长)必须仍然成立 —— 分诊指出它在 604 时比在 532 时更成立。⛔ 不要把论点一起删掉。
    4. ⭐ 反向读:scripts/docs-audit/ 里还有没有别的裸数字是同一种句子?零结果也报。

    PR 开 draft,Closes #16200。

    通用边界

    • worktree-first;⛔ 不 git stash;⛔ 已推分支不 rebase / amend / force-push。
    • ⛔ 不碰 content/docs/releases/、docs/adr/**、AGENTS.md、CLAUDE.md。
    • ⭐ 反向读 diff:这处改动让树里哪一句现存的话变成假的?动手前扫一遍,把零结果也报出来 —— 零才是一次阅读,不是一次沉默。
    • ⭐ 树上若有钉住当前行为的用例,就地重判并写明理由,⛔ 不许删。
    • ⭐ commit trailer 用 model-free 对(AGENTS.md:440-444):Claude-Session: https://claude.ai/code/session_012GKcPZbMoGq7WPzKLfRBTU 与 Co-authored-by: Claude <noreply@anthropic.com>。⛔ 任何推送产物里不许出现模型标识。
    • Clause-② 卡面载体本席已在上面落好;PR 正文那个载体是你的,行首写,发前 readClause2Line() 自验。
    • ⚠️ MCP 可能掉线或限流;容器 GITHUB_TOKEN 的 REST 通道可用,GraphQL 被禁。
    • changeset 先量再判;判 skip 就打 skip-changeset 标签 —— ⭐ 它是标签,⛔ 不是正文一句话。

    Generated by Claude Code

  4. claude commented on Sep 12, 2026

    @claude
    Contributor

    os-dev-report

    {
      "issue": 16200,
      "status": "done",
      "branch": "claude/issue-16200-docs-audit-stale-figures",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/17795",
      "premise_still_valid": true,
      "summary": "Both carriers now name check:authorable-surface as the thing that prints the current delta on every run (disposition 1, triage's preferred shape), and no number was written back into either. scripts/docs-audit/README.md line 124 and the AUTHORABLE_KEY_SUFFIX_RE docblock in scripts/docs-audit/affected-docs.mjs line 469 lost the 532; the docblock and one verbatim copy of the same sentence in the --self-test battery (affected-docs.mjs line 3473) lost the 103. The argument those sentences support is kept and restated 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. I re-measured the figures myself (they moved again) and used them only as PR-description evidence for removing them, each carrying its rev and date. Assignee was already set by the PM and I did not touch it; no second Claim was posted.",
      "tests": "All 34 gate families derived by `node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack` for this change set were run in the worktree; every one exited 0, and `--ran` reconciliation with exit codes recorded reports: '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)'. Load-bearing verdict lines: `pnpm check:docs-audit-scope` printed 'affected-docs self-test: 585 cases pass.' and 'check-audit-scope self-test: 32 cases pass.' and '195 hand-written doc(s)'; `node scripts/docs-audit/check-affected-docs.mjs` exit 0 (it is the discoverable wrapper for affected-docs.mjs --self-test, and no *.test.ts in the tree names affected-docs, so it is that script's whole suite - rule 5 discharged); `pnpm --filter @objectstack/spec run check:authorable-surface` exit 0. Exit codes were captured by redirecting to a log before any pipe, never read through one. Spec was built first under `bash scripts/pm/os-verify-lock.sh -c` (VERDICT command-exit 0, held 143s, waited 0s) so no gate read a stale dist. NO ABLATION was run and none is owed: this diff adds no guard, changes no branch and has no failure mode to prove - it deletes three figures from comments and prose. Instead the MECHANISM the fix points at was measured rather than assumed: check:authorable-surface printed on this tree 'authorable-surface.base.json trails the baseline at 952b9c5e59b7: it mirrors the older 53ef05744f37, and they differ by 970 key(s) only that baseline has, 1034 only the anchor has', and those two counts reproduce byte-exactly from the raw key sets of packages/spec/authorable-surface/*.json versus authorable-surface.base.json - so the instrument really does answer the question the deleted sentences answered. Control-character sweep clean on both edited files (`grep -naP` over the non-tab/newline control range) plus `pnpm check:nul-bytes` exit 0. Repo-wide `pnpm lint` deliberately NOT run and no narrowing claimed in its place - it is the CI-owned run; no edited file carries executable behaviour.",
      "mcp_calls": "0 - the whole run used the container GITHUB_TOKEN REST channel and git only; zero MCP GitHub calls. Channel note: the REST /search/issues endpoint answers 403 here ('sessions are bound to their configured repositories'), so a duplicate search was not available on the cheap channel. I did not spend the sanctioned one-shot MCP search_issues either, because I filed nothing - see out_of_scope_findings.",
      "open_questions": [],
      "out_of_scope_findings": [
        "noted, not filed: scripts/docs-audit/README.md states the hand-written corpus as '178 pages' in roughly five places (lines ~188, ~192, ~493, ~627), unanchored, while check:docs-audit-scope prints '195 hand-written doc(s)' on this tree. Each 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 defensible reading - but 'the anchor derivation reads the same 178-page corpus the old one did' is written in the present tense. NOT filed because triage ruled explicitly that a repo-wide hunt for hard-coded counts 'is a different card with its own population'; opening that population card is the PM's act, not a rider on this one. Successor: the domain:devx PM seat.",
        "noted, not filed: two further 'measured on this tree' live-claim sentences exist OUTSIDE scripts/docs-audit/ - scripts/check-bash32-floor.mjs line ~121 (names files, no count) and scripts/pm/dispatch-gates.mjs line ~8307 ('it is one of the six', which IS a count). Same population as the finding above and out of this card's directory by the same triage boundary. Successor: the same population card.",
        "noted, not filed: REVERSE-READ ZEROS, reported as readings and not as silence. (1) 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 quoted the figures these carriers held. (2) Hard-coded shard count 11 anywhere in scripts/docs-audit/: ZERO - the card's third figure came from #14612's triage comment, never from a carrier in this directory, so there was nothing here to repair and the 11 to 14 decay has no landing site. (3) Sentences elsewhere in the tree that THIS diff makes false: ZERO - no pin, fixture, gate, workflow or doc reads these sentences; the repo-wide grep above is that reading. (4) affected-docs.mjs line ~1344 uses the identical 'Measured on this tree' phrasing but was re-verified and is STILL TRUE: zero commands declare `static topic` under packages/cli/src/commands/, and the one `static id` is packages/cli/src/commands/init.ts line 912, `static override id = 'init'`, which agrees with its path. It is also a claim about a zero whose failure direction the docblock itself names, not a decaying magnitude - so it is not this defect class. (5) affected-docs.mjs line ~6019 uses the phrasing correctly: it carries its rev (`f5a7f9c88`, 7 warm runs). No repair owed on either.",
        "noted, not filed: the third carrier was fixed IN THIS PR rather than deferred - the --self-test battery at affected-docs.mjs line 3473 held a verbatim copy of the same '103 of them' sentence. Leaving it would have left one site in the same file asserting a figure this PR removes from the docblock ~3000 lines up: a contradiction created by this change rather than inherited. It meets all four bounded-in-place conditions (same defect class, mechanical with the shape already pinned by the sibling edit, no other claim on the file, same gate family, no new verification surface) and is named with its evidence in the PR description."
      ],
      "figures_remeasured": {
        "measured_at": "952b9c5e59b7 on 2026-09-12, by the dev seat, using the tool's own AUTHORABLE_KEY_SUFFIX_RE to strip the annotation",
        "live_ratchet_keys_absent_from_anchor": "532 as written -> 604 at d5d8d50db (card) -> 863 here; 62% movement in ten days",
        "annotated_RETIRED_class_keys": "103 as written -> 206 at d5d8d50db (card) -> 209 here",
        "shard_files_under_packages_spec_authorable_surface": "11 as written -> 14 at d5d8d50db (card) -> 14 here",
        "note": "None of these numbers is written into the tree by this PR. They appear only in the PR description, each carrying its rev and its date, as the evidence for removing the bare ones."
      },
      "disposition_per_carrier": {
        "scripts/docs-audit/README.md (line 124)": "disposition 1 - points at check:authorable-surface. The historical figure was doing no work the live delta cannot do, so disposition 2 would have been the weaker version triage warned about.",
        "scripts/docs-audit/affected-docs.mjs AUTHORABLE_KEY_SUFFIX_RE docblock (lines 469, 479)": "disposition 1 for both the 532 and the 103, same reasoning; the docblock additionally now says out loud that the lag is deliberately NOT stated as a number here, so the next author does not helpfully restore one.",
        "scripts/docs-audit/affected-docs.mjs --self-test comment (line 3473)": "disposition 1, bounded in-place - verbatim duplicate of the docblock's 103 sentence."
      },
      "changeset_judgement": "skip-changeset LABEL applied to PR #17795 (a label, not a body sentence), 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 reaching scripts/ - checked across every packages/**/package.json, with a positive control (packages/spec's files[] resolves to real published paths: dist, json-schema, api-surface, ...), so the zero is a measurement and not an empty scan. Label write used the additive POST .../issues/17795/labels endpoint and was confirmed by a comparative read-back: stored set is size/s + skip-changeset, nothing from the target set missing, nothing stripped.",
      "clause_2_judgement": "no. The diff changes explanatory prose in repo tooling only - no spec schema, no published exports, no wire shape, no authorable key, so a contract review has no surface to review. The card-side carrier the PM placed also reads no. The PR-body carrier is line-initial and was self-verified with readClause2Line(), which returned kind 'declared', value 'no'. No needs:contract-review label applied, and --pair was therefore not run.",
      "unsettled": "Nothing blocking. CI on PR #17795 had not converged when this report was filed - that wait is the PM's, per the dispatch contract, and the 34 locally-derived gate families are all green. The PR is a DRAFT and auto-merge is NOT armed; arming is the PM's act. No governed surface is in the file list."
    }

    Generated by Claude Code

  5. github-actions commented on Sep 12, 2026

    @github-actions
    Contributor

    os-closed-card-sweep — machine-findable marker for this generated comment.

    Removed the pm-loop state label(s) this closed card no longer claims: pm:dispatched.

    A state label claims work is in flight. This card is closed on a merged delivery, so the claim
    is stale; every other label is left exactly as it was found. Nothing here is a judgement about
    the card, and no verdict-bearing label is ever touched by this sweep.

    posted by half-state-patrol run 34681361467 · trigger schedule

    Generated by Claude Code

  6. added 2 commits that reference this issue on Sep 17, 2026
    495c263
    bc1f467
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions