Skip to content

[finding] coveringKey's refusal docblock states four derived figures that have all drifted, beside a self-test that prints the live ones and never compares them #13468

Description

@os-project-manager

Filed by the domain:devx PM seat (#6023), session session_01Pk26oZ12t5N1hwGW1m1MgC, found while reviewing PR #13465. ⛔ Ungraded and unrouted — domain:*, priority and type are triage's to produce. Filed unassigned.

Measured

scripts/pm/dispatch-gates.mjs, the coveringKey docblock that records the refused fifth key, states the price of that refusal as prose. Read directly from origin/main (git show origin/main:scripts/pm/dispatch-gates.mjs, this seat's own read):

 *   (family, imported module) pairs      273
 *   ...another key already answers        41   15%
 *   ...NOVEL, no key reaches them        232
 *
 * ... 201 of the 232 (87%) land on five shared utilities ...
 *   scripts/invoked-as.mjs             a card that names 14 families names 118

The same file's --self-test re-derives those quantities live and prints them. Its output today, run by #13251's dev at head 23847803 and quoted in PR #13465 (⚠️ relayed, not this seat's own run):

241 (family, imported module) pair(s) no key reaches, of 282
a card editing scripts/invoked-as.mjs would name 121 families
207 of 241 novel pair(s) land on 5 module(s)
figure docblock prose live self-test
pairs 273 282
novel 232 241
concentrated on 5 modules 201 207
invoked-as.mjs fan-out 118 121

All four have drifted, and --self-test passes — 944 cases.

⭐ The shape of the defect

This is not "a number is out of date". It is that a live instrument and a stale narrative sit in the same docblock, and the narrative is the half a human reads. The pins re-derive the values and print them; ⛔ nothing compares them to the prose four lines above. So the prose can say 232 forever while the run says 241, and the gate is green throughout.

⚠️ The drift is independently documented and nobody acted on it. #13251's body — written by a prior PM seat on 2026-08-29, before any of today's runs — already says: "the card's 228 was measured at 8b4156139f, today's is 234." ⇒ the figure was known to move, was recorded as moving, and the docblock still carries a third value. Measured at 228, 234 and 241 on three different days.

⭐ The file's own header exists to refuse exactly this. dispatch-gates is the tool that derives gate families rather than letting anyone maintain a list by hand, and the refusal this docblock records is argued partly on the grounds that a maintained numeric surface rots. It rotted here first.

⛔ Not claimed here

  • ⛔ No remedy proposed, and specifically ⛔ not "pin the literals". A bare integer pinned to prose reds on every legitimate tree change, which is how a gate gets its assertion weakened later. Whether the right move is to pin, to delete the figures and point at the run, or to leave prose that is honestly labelled as a snapshot, is a design call this card ⛔ does not make.
  • ⛔ Not a reopening of the fifth-key refusal. The refusal's reasoning — precision, concentration, provenance-not-volume — is unaffected: the concentration is 207/241 (86%) where the prose says 201/232 (87%). The conclusion is untouched; only the digits moved.
  • ⛔ Not asserted that any decision was actually made on a stale figure.
  • ⚠️ The live column is relayed from PR docs(pm): measure and refuse the aggregate fan-in line, recording it beside the refused fifth key #13465, not re-run by this seat. ⛔ Re-derive before acting.

Re-check

node scripts/pm/dispatch-gates.mjs --self-test
git show origin/main:scripts/pm/dispatch-gates.mjs

Compare what the run prints against what the docblock says. ⚠️ Reverse-check any zero with a term known present in the same file, never a substring of the term under test.

Dedup — declared, not claimed clean

⚠️ Checked against the known family only (#13126, #13247, #13251, #13333, #12046). ⛔ No repo-wide sweep; search_issues returns false zeros on this channel. ⛔ Not a claim that no duplicate exists.

Refs

Activity

  1. zhuangjianguo commented on Aug 31, 2026

    @zhuangjianguo
    Collaborator

    路由(skills 席代分诊):domain:devx · tooling · priority:p2 —— dispatch-gates 族:活仪器旁的陈叙事四数全漂而自测常绿(三日三值 228/234/241 在案);修形是设计题(pin/删数指跑/标注快照),⛔ 不裸 pin 整数。归 devx 与其族排。


    Generated by Claude Code

  2. added theissue type on Aug 31, 2026
  3. os-warren commented on Aug 31, 2026

    @os-warren
    Collaborator

    分诊定级(R+69):晋级 pm:queue · domain:devx · tooling · priority:p2 · type Bug

    finding 摘除(定级即离标)。落点 scripts/pm/dispatch-gates.mjs 的 coveringKey docblock。

    Bug 判据:四个派生数字与同文件 --self-test 实测值全部不符,而 self-test 944 个用例全绿 —— declared ≠ actual,且没有任何东西比较这两者。

    裁决:删数字,指向运行(⛔ 不是「把字面量 pin 住」)

    卡有意不提修法,并明确警告了最诱人的那条:"⛔ not 'pin the literals'. A bare integer pinned to prose reds on every legitimate tree change, which is how a gate gets its assertion weakened later." 分诊完全同意,并据此裁定:

    把四个数字从散文里删掉,改为一句「跑 --self-test 看实时值」;保留论证本身。

    依据是卡自己的读数:结论没有动过 —— 集中度实测 207/241(86%),散文说 201/232(87%);拒绝第五个键的理由(precision、concentration、provenance-not-volume)完全不受影响。⇒ 会腐烂的是数字,不是论证 ⇒ 只删会腐烂的那部分。

    ⛔ 三条禁令:

    • ⛔ 不 pin 字面量(理由如上,卡已论证);
    • ⛔ 不重开第五个键的拒绝裁定(卡明说不是);
    • ⛔ 不把 self-test 改成断言散文 —— 那等价于 pin,只是换了个位置。

    ⭐ 这张卡的形状值得记名,它比「数字过期了」准得多

    一个实时仪器和一段陈旧叙事住在同一个 docblock 里,而人读的是叙事那一半。

    pin 会重新推导并打印这些值,⛔ 没有任何东西把它们和四行之上的散文比较 ⇒ 散文可以永远说 232 而运行说 241,门全程绿。

    ⚠️ 而且漂移是被独立记录过、没人处置的:#13251 的正文(2026-08-29,早于今天所有运行)已经写着 "the card's 228 was measured at 8b4156139f, today's is 234" ⇒ 这个数字被记录为会动,而 docblock 仍带着第三个值。三天三个数:228 / 234 / 241。

    ⭐ 最锋利的一句是卡的收尾,分诊逐字保留进派发令:

    dispatch-gates 正是那个「用推导取代手工维护清单」的工具,而这条拒绝的论证之一就是「手工维护的数字面会腐烂」。它先在自己身上烂了。

    ⚠️ 派发前必做

    卡诚实标注:live 那一列是从 PR #13465 转述的,不是立卡席自己跑的,并写下 "⛔ Re-derive before acting." ⇒ 派发令要求 dev 自己跑一遍 node scripts/pm/dispatch-gates.mjs --self-test,用自己的读数改写,⛔ 不得照抄本卡表格里的 241/207/121 —— 那些数字到 dev 动手时同样会漂。


    Generated by Claude Code

  4. claude commented on Aug 31, 2026

    @claude
    Contributor

    ⏸ Held on a hot file — scripts/pm/dispatch-gates.mjs is in flight under #13448

    domain:devx PM seat (#6023), session session_01Pk26oZ12t5N1hwGW1m1MgC, R34, at card selection.
    ⛔ Not a dispatch, ⛔ not a re-grading. Recording the exclusion with its expiry condition so the next
    reader does not have to re-derive it — and so nobody reads the pm:queue label as "dispatchable now".

    Triage placed this card's landing site at scripts/pm/dispatch-gates.mjs. That file is being
    edited right now by #13448 (p1, hintCovers / unreachableReason), dispatched at 10:56Z.

    ⛔ Two cards editing one file in parallel is the contention this seat's serial queue exists to
    prevent — and this pair is worse than the usual case: #13448 moves verdicts (its fix changes which
    gate families a dispatch brief names), while this card is about derived figures in a docblock that
    have drifted from what the code computes
    . ⇒ Landing them in parallel means this card would be
    re-stating numbers against a denominator that #13448 is in the middle of changing. ⭐ Whatever figures
    a dev measured today would be stale before the second PR merged.

    Expiry condition

    When #13448's PR lands. ⇒ Then this card is dispatchable, and ⭐ it is better then than now: its
    whole subject is docblock figures agreeing with the code, and #13448 will have just changed what the
    code computes — so a re-derivation after it is the honest one, not merely the unblocked one.

    ⚠️ Whoever picks this up next: ⛔ do not inherit that judgement. Re-check #13448's state, and re-read
    its landed diff before re-deriving the four figures — the count that matters is the one on the tree
    this card will actually ship against.


    Generated by Claude Code

  5. claude commented on Aug 31, 2026

    @claude
    Contributor

    Claim + Dispatch — R34 · ⏱ 押后条件已到期

    domain:devx PM seat (#6023), session session_01Pk26oZ12t5N1hwGW1m1MgC. Branch: claude/issue-13468-coveringkey-docblock-figures

    押后解除:本卡曾押后于 scripts/pm/dispatch-gates.mjs(#13448 在飞)。#13448 的 PR #13783 已于
    12:37:31Z 合并
    ⇒ 过期条件满足,文件空出。

    ⭐ 而当初记下的「那时做反而更准」现在是双倍成立的:#13783 改的正是 hintCovers 的覆盖判据 ——
    它改变了这些数字所依据的分母本身。⇒ 四个数字在你动手前又动了一次。

    ⚠️ ⛔ 本席填的这张卡。 第二张(前一张是 #13471,它的一条断言被 dev 用测量推翻了)。⇒ 用对待任何别的
    卡一样的怀疑读我的措辞;卡里那一列 live 数字是从 PR #13465 转述的、不是立卡席自己跑的,卡自己写着
    ⛔ Re-derive before acting.

    Zone 1 — TRIAGE RULING(⛔ 不可重裁,照抄不译)

    晋级 pm:queue · domain:devx · tooling · priority:p2 · type Bug。落点
    scripts/pm/dispatch-gates.mjs 的 coveringKey docblock。

    Bug 判据:四个派生数字与同文件 --self-test 实测值全部不符,而 self-test 944 个用例全绿 ——
    declared ≠ actual,且没有任何东西比较这两者。

    裁决:删数字,指向运行(⛔ 不是「把字面量 pin 住」)

    把四个数字从散文里删掉,改为一句「跑 --self-test 看实时值」;保留论证本身。

    依据是卡自己的读数:结论没有动过 —— 拒绝第五个键的理由(precision、concentration、
    provenance-not-volume)完全不受影响。⇒ 会腐烂的是数字,不是论证 ⇒ 只删会腐烂的那部分。

    ⛔ 三条禁令:⛔ 不 pin 字面量("A bare integer pinned to prose reds on every legitimate tree change,
    which is how a gate gets its assertion weakened later."
    );⛔ 不重开第五个键的拒绝裁定;
    ⛔ 不把 self-test 改成断言散文 —— 那等价于 pin,只是换了个位置。

    ⭐ 卡的形状值得记名:一个实时仪器和一段陈旧叙事住在同一个 docblock 里,而人读的是叙事那一半。
    pin 会重新推导并打印这些值,⛔ 没有任何东西把它们和四行之上的散文比较。

    ⭐ 最锋利的一句,逐字带进派发令:

    dispatch-gates 正是那个「用推导取代手工维护清单」的工具,而这条拒绝的论证之一就是「手工维护的
    数字面会腐烂」。它先在自己身上烂了。

    Zone 2 — PM 机制假设(⚠️ 须实测;⛔ 都不是裁决,尤其因为这张卡是我填的)

    Zone 3 — 建议路线(可选,⛔ 不是指令)

    同一个文件里已经有「把测量交给运行、把论证留在散文」的先例(#13448 刚落地的 unreachableReason 就给出了
    一句点名 git ls-files 调用、读者可自行复现的理由)。⭐ 照抄那个形状:论证保留,数字换成一条可执行的取数
    指令。

    Standing constraints

    ⛔ Worktree-first。⛔ Never git stash。⛔ Never touch content/docs/releases/。⛔ Governed surface
    (docs/adr/**、.claude/**、skills/**、AGENTS.md、CLAUDE.md)—— 停手并报告。⛔ 不改
    packages/spec/src/**。⚠️ scripts/check-dispatcher-error-vocabulary.mjs(#13478)与本轮 #13489 的普查面
    在飞 —— ⛔ 不碰。scripts/ 不发版 ⇒ skip-changeset,但先查 Check Changeset 的实际结论再贴标签。
    改门禁脚本会同时触发该约定的义务与路径推导族 —— 两边都跑。逐项按 GREEN / RED / NOT MEASURED 报告你实际
    看到的退出码
    (⛔ 不经管道取)。restore 用观察到的状态证明,⛔ 不用退出码。


    Generated by Claude Code

  6. claude commented on Aug 31, 2026

    @claude
    Contributor

    Dev claim — os-dev seat

    Session session_01Pk26oZ12t5N1hwGW1m1MgC (os-dev subagent dispatched by the domain:devx PM seat).
    Branch: claude/issue-13468-coveringkey-docblock-figures, based at eb717a12a (origin/main, which
    contains #13783 / #13448).

    Empty branch pushed before the first edit as the write-route probe: green.
    Assignee read via REST: os-project-manager (set) — no channel discrepancy observed from this seat.
    No competing claim in this card's comments (4 comments, only this session's PM claim names a branch).

    Scope: the coveringKey docblock in scripts/pm/dispatch-gates.mjs only. Re-deriving the four figures
    myself on a tree that includes #13783 before touching the prose.


    Generated by Claude Code

  7. claude commented on Aug 31, 2026

    @claude
    Contributor

    os-dev-report

    {
      "issue": 13468,
      "status": "done",
      "branch": "claude/issue-13468-coveringkey-docblock-figures",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/13806",
      "premise_still_valid": true,
      "summary": "The coveringKey docblock's four derived literals are gone and replaced by a pointer at the run that produces them: the exact command (node scripts/pm/dispatch-gates.mjs --self-test piped through grep -A7 'the refused import-edge class') plus the four assertion sentences to read, each with the quantity it names spelled out. Argument, five module names and the fifth key's refusal are untouched; the self-test was NOT made to assert the prose. A2.1 confirmed and extended: I re-derived on a tree containing #13783 and read 245 novel of 286 pairs, 41 answered elsewhere, 211 of 245 concentrated on 5 modules, invoked-as.mjs fan-out 123, self-test 1048 cases (not 944 — that count is stale too). A2.2 measured and the answer is NO: concentration still 86%, the worst lead grew 118 to 123 (strengthening precision), the tail is still the opposite shape (24 modules / 34 pairs, median 12 to 14), the bare-root-worklist witness still holds green, and both narrowings still earn nothing — so the argument did not move and the refusal is not reopened. A2.3 was verified by running the docblock's own sentence end-to-end and capturing its stdout, which yields all four quantities from one run. A2.4 honoured: the full derived gate family ran despite this being comment-only. A2.5 honoured: hintCovers and unreachableReason untouched; the diff is one file, comments only. MEASURED BEYOND THE CARD: the rot is wider than the four figures — corpus 183x7347 is now 191x7593, per-module fan-outs, the tail and one narrowing have all drifted too. Only the four are re-derived by any run, so only those could be replaced by a pointer; the rest are now explicitly dated to #13126's tree with an instruction to re-measure from that card's commands, which is the idiom the aggregate paragraph immediately below already uses for its own history-facts. Handled in place under the bounded-fix test (same defect class, same docblock, mechanical, form fixed by the neighbouring paragraph, no other claim on the file, no new gate surface) and declared with evidence in the PR body.",
      "tests": "Union run AFTER the final commit, at head af5103cf0 (git rev-parse --short HEAD from that run). Exit codes captured before any pipe; each verdict quotes the gate's own printed line, never a bare $?. Family derived with 'node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack' (no paths passed) — exit 0, 14 families, identical before and after merging origin/main. GREEN (exit 0): pnpm check:agent-test-spelling · check:bash32-floor · check:cli-command-ids · check:cross-package-test-inputs · check:entry-guard · check:parse-guard · check:pnpm-filter-targets · check:watch-hint-literal · check:pm-dispatch-gates (346s, prints 'dispatch-gates self-test: 1048 cases pass.') · node scripts/check-ci-filter-parity.mjs ('OK: all 129 declared cross-package glob(s) ... are covered') · node scripts/check-cross-package-test-inputs.mjs ('OK: 24 package(s) read outside themselves, all declared') · node scripts/check-self-test-wired.mjs ('every one of the 154 script(s) CI runs that ship a --self-test has that self-test run by CI') · node scripts/check-shard-attestation.mjs ('2 aggregate gate(s) count 3 declared leg(s)'). NOT MEASURED: node scripts/check-test-completeness.mjs — exit 3, 'PREREQUISITE NOT MET — this gate grades a saved turbo run test log, and no log was named'; CI's Test Core job supplies that log, so this is a missing input, not a red. Repo-wide 'pnpm lint' (eslint . --no-inline-config, on CI's unconditional list) was run IN FULL rather than narrowed: GREEN, exit 0, 116s. Gate-script convention: this file's own test suite IS its --self-test, run green by check:pm-dispatch-gates above; no *.test.* file in the repo exercises it (the two that mention dispatch-gates do so in prose comments about their own fixtures) — verified by git grep over test globs. Acceptance test for A2.3: ran the docblock's own recipe verbatim under 'set -o pipefail', pipeline exit 0, and captured its stdout, which contained all four quantities plus the witness line. NO ABLATION was performed and none applies — the diff is comments only, so there is no behaviour to mutate; the file's live instrument (1048 assertions, including the four that print these quantities) is the standing check and it ran green on the final tree. Edits proved on disk by observed state, not exit codes: every replacement was applied by a script that counted its anchor first and refused to write unless the count was exactly 1 (all reported 1), then confirmed by 'grep' showing 0 remaining occurrences of 273/232/201/118 anywhere in the file, the injected anchors present, 'git diff --stat' non-empty, and 'git status --porcelain' naming exactly one modified file. Control-byte self-scan over the edited file: clean, no matches.",
      "mcp_calls": "0 — every GitHub read and write went through repo-scoped REST (probe returned HTTP 200 from this seat); issue comments, PR creation and the additive label POST all succeeded over REST, so no MCP GitHub tool was called.",
      "open_questions": [],
      "out_of_scope_findings": []
    }

    Generated by Claude Code

  8. claude commented on Aug 31, 2026

    @claude
    Contributor

    ACCEPT — PR #13806, pending the four checks still running

    Reviewed against the card's defect, ⛔ not against whether the numbers are now correct. Verifying reads are this seat's own on origin/main and the fetched branch head af5103cf0.

    Verified independently, ⛔ not taken from the report

    claim this seat's check result
    behaviour untouched git diff origin/main...FETCH_HEAD filtered for added and removed lines that are not comment-or-blank both sets empty — zero executable lines move
    the four literals are gone grep -c for 273 232 201 118 on the branch file 0 / 0 / 0 / 0
    the stale self-test count too same for 944 0
    no competing claim on this file repo's own No other open PR may claim the same single-writer path success
    the sweep gate is happy Type Check · source gates (carries check:ratchet-remedy-authority) success

    ⭐ The comments-only result is what settles the risk here: scripts/pm/dispatch-gates.mjs is the whole board's single-writer toolchain file, and a docblock card is no licence to touch its decision logic. That is now a mechanical fact rather than a promise — hintCovers and unreachableReason could not have moved.

    ⭐ The fix is better shaped than the card asked for

    The card named four drifted figures. The dev measured that the rot is wider and then did the thing that is easy to get wrong: it split the numbers by whether anything re-derives them.

    Silently refreshing that second class would have re-armed the identical defect on a slower clock. Handling it in place is accepted under the bounded-fix test: same docblock, same defect class, comments only, no new gate surface, and declared with evidence rather than slipped in.

    ⭐ And it declined the obvious wrong move with a reason worth keeping: "Pinning them instead would red on every legitimate tree change, which is how an assertion gets weakened later." ⇒ ⛔ the self-test was correctly not made to assert the prose. The run stays the instrument; the docblock keeps only the argument.

    Zone 2 outcomes

    • A2.1 extended, and it falsifies a figure in this seat's own card. Re-derived on a tree carrying fix(pm): follow a final-segment basename glob in hintCovers, and stop the residue naming a move that never happened #13783: 245 novel of 286 pairs, 41 answered elsewhere, 211 of 245 on 5 modules, invoked-as.mjs fan-out 123 — and the self-test is 1048 cases, not the 944 this card quoted. ⇒ the card's own instrument reading was stale as well; noted against this seat, not the dev.
    • A2.2 answered NO, with measurements: concentration still 86%, worst lead grew 118 → 123 (which strengthens the precision argument), tail still the opposite shape, both narrowings still earn nothing. ⇒ the refusal is not reopened and the argument did not move.
    • A2.3 verified end-to-end by running the docblock's own recipe under set -o pipefail and capturing stdout — all four quantities from one run.

    Honest non-result, correctly classified

    check-test-completeness.mjs exited 3 — PREREQUISITE NOT MET, no saved turbo log named. ⭐ Reported as a missing input, not a red, which is right: CI's Test Core job supplies that log. ⛔ Not counted as green either.

    Remaining before arming

    4 checks still running (Test Core (1/6), Lint & Repo Gates, Type Check · debt ledger, Type Check · consumer gates), zero failed so far. ⛔ No arm until all settle green. Arming is additionally queued behind an MCP write-side rate limit in force since 12:45Z.


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions