Skip to content

docs(pm-dispatch): an enumeration that cannot say it was truncated may not report clean - #13098

Merged
os-zhuang merged 3 commits into
mainfrom
claude/issue-12817-enum-truncation
Aug 29, 2026
Merged

docs(pm-dispatch): an enumeration that cannot say it was truncated may not report clean#13098
os-zhuang merged 3 commits into
mainfrom
claude/issue-12817-enum-truncation

Conversation

@os-litant

@os-litantos-litant commented Aug 29, 2026

Copy link
Copy Markdown
Collaborator

Fixes#12817

What was wrong

The two-tier triage inventory section (references/dispatch-runbook.md, maintainer ruling
2026-08-20) tells each hourly read-method what to enumerate — sweep 析取, 解锁扫描反演,
健康指标 — but never required any of them to check that it had finished. A list read that
returns fewer items than totalCount proceeded silently, and the scan's own output could not
distinguish a complete reading from a partial one.

Measured 2026-08-27: an enumeration ran at perPage=50 against a totalCount of 51. One card
was never examined. Nothing printed distinguished "read all of them" from "read all but one" —
the caller saw a list and proceeded.

This is the same collapse class the tree-staleness cards name: an incomplete reading and a
complete reading print the same thing.

What changed

Three sentences appended to the paragraph that already specifies the hourly layer's three
read-methods — the completeness predicate lands where the enumerations are defined, not as a
second procedure, and appending costs no separator line:

  • every enumeration compares its returned count against totalCount;
  • a shortfall means the round 没读完 — it reports sweep INCOMPLETE naming the gap, and
    ⛔ may never be reported clean, the standard check-governed-merges.mjs already applies to
    unaudited repos;
  • pagination 只治当次 — it cannot fix the next list to outgrow the page size, which is why the
    rule is one predicate and ⛔ not a second code path.

Out of scope and untouched, per the 2026-08-24 ruling recorded in platform-readings.md: where
Blocked-by: lives, and the body-only read direction. No issue numbers were written into the
protocol text — the entry carries a date, per the file's own 行文纪律.

Ratchet

The file sits at its ceiling with zero headroom, so the rule is paid for by deletion in the same
file. No ceiling was raised.

fileceilingbeforeafterheadroom
.claude/skills/pm-dispatch/references/dispatch-runbook.md2742742740

Verdict line, from the union run on the final commit:

check-skill-line-ratchet: .claude/skills/pm-dispatch/references/dispatch-runbook.md is 274 lines (ceiling 274; headroom 0).

Cut ledger — net 0 (+3 rule, -3 deleted content)

⚠️ The first commit on this branch (b4160a5) funded the rule by re-wrapping orphan
continuation lines with no prose deleted. That is banned outright by the ratchet's governing
clause, quoted verbatim (maintainer 2026-08-17, SKILL.md):

⛔ re-wrap(折行合并)不得用作筹行 —— 棘轮治理的是内容体量,行数只是机读代理,新增以删减付账;密度优化仅随净减内容的 PR 顺带

Content volume net-increased while the line count stayed flat — the exact shape the clause
forbids. Commit ac9ceed reverts every re-wrap: those five paragraphs are byte-identical to
origin/main again, and the rule was compressed from six lines to three. The funding is now
real deletion, each cut with a surviving home:

cutlinessurviving home
the 落卡分析模板 + 业务写法六项 pointer bullet2references/decision-analysis.md carries the template, the six writing requirements, the 四棱块 shape and both ruling dates (中文 2026-08-19 at its line 17; 业务角度 2026-08-20 verbatim at its line 3); SKILL.md already routes readers there. The bullet was a routing stub, which the file's own header excludes — it holds 细则增量, not signposts to other files.
the 惰性判定 back-pointer1references/seat-post-protocol.md states the same lazy/standing split from the other end — 「惰性半边在接管冲突时评估一次 … 常设半边是分诊轮的座位贴活性巡查,同一判据」 — and points back to this file for the details the deleted line merely re-announced.
new rule text-3appended to the existing paragraph (no separator line needed)

The resulting diff against origin/main is 4 insertions / 4 deletions in one file, with no
re-wrapped line anywhere in it.

Serialization with PR #13106

PR #13106 also edits this file and is accepted ahead of this one; it lands first. Its cuts are
四件补遗 items ② and ④, the pnpm --workspace-concurrency sentence, and the rejection-envelope
clause. This PR double-claims none of them — verified against its branch: it keeps the
落卡分析模板 pointer bullet as unchanged context, and never touches the 惰性判定 line in the
座位贴活性巡查 section. The two cut sets are disjoint, and the file is 274/274 under either
order, so the net-0 arithmetic holds whichever lands first.

At the time of writing #13106 had not merged, so this branch is merged up to origin/main
d48929e instead. Its new bullet lands in the same section this PR deletes a bullet from, so a
textual merge may need a hand at landing time.

Gates

Derived with node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack (no paths
passed; the script took the change set from the merge base itself — 1 path). All eight ran as
one && chain on the final commit e215a64, exit 0 — each verdict quoted from the gate's
own output, never from a bare shell status.

gateverdict line
check:pm-skill-ratchetdispatch-runbook.md is 274 lines (ceiling 274; headroom 0)
check:pm-skill-id-lint23 file(s) clean (pattern /#[0-9]{3,}/g)
check:agent-test-spelling0 violations — 398 file(s)
check:doc-authoring392 files clean — no bare metadata literals
check:doc-formula-expressions22 record-scoped formula example(s) across 425 files / 1453 TS blocks judged clean
check:pm-governed-merges--self-test: 206 assertions
check:skill-frame-sync4 copies of the decision frame are structurally isomorphic across 3 files
check:nul-bytesOK (scanned 7285 text file(s) ... no raw ASCII control bytes)

@objectstack/formula and @objectstack/lint are built first in the same chain —
check:doc-formula-expressions otherwise exits PREREQUISITE NOT MET, which is the gate
declining to measure, not a red.

Changeset

None. The diff is .claude/ protocol text only and publishes nothing, so the PR carries
skip-changeset.

Generated by Claude Code

…y not report clean
The two-tier triage inventory told each hourly read-method WHAT to enumerate but
never required it to check that it had finished. A list read returning fewer
items than `totalCount` proceeded silently, and the scan's own output could not
distinguish a complete reading from a partial one.
Adds the completeness predicate to the section that owns the three read-methods:
compare returned count against `totalCount` on every enumeration, and report
`sweep INCOMPLETE` naming the gap when they differ -- never as a clean scan.
Paginating alone is only half the answer, because the next list to outgrow the
page size reintroduces it. Same standard `check-governed-merges.mjs` already
applies to unaudited repos.
Paid net-0 against the file's ratchet ceiling by rewrapping five paragraphs
whose hard wraps had left orphan continuation fragments; content is
byte-identical modulo whitespace.
Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MnijPVVDakqK2J335JoJtq
@github-actionsgithub-actionsBot added size/s documentation Improvements or additions to documentation labels Aug 29, 2026
@os-litantos-litant added skip-changeset PR has no user-facing published change; bypasses the changeset gate and removed documentation Improvements or additions to documentation size/s labels Aug 29, 2026 — with Claude
The first commit paid for the rule by re-wrapping orphan continuation lines,
which the ratchet's governing clause bans outright: 「⛔ re-wrap(折行合并)不得
用作筹行 —— 棘轮治理的是内容体量,行数只是机读代理,新增以删减付账;密度优化仅随净
减内容的 PR 顺带」 (maintainer 2026-08-17). Content volume net-increased while
the line count stayed flat -- the exact shape the clause forbids.
Every re-wrap is reverted; the five paragraphs are byte-identical to origin/main
again. The rule is compressed from six lines to three and appended to the
paragraph that already specifies the hourly layer's three read-methods, so it
costs no separator line.
Paid instead by deleting three lines of genuine duplication, each with a
surviving home:
- the 落卡分析模板 + 业务写法六项 pointer (2 lines) -- a routing stub whose
every element, both ruling dates included, lives in
references/decision-analysis.md, which SKILL.md already routes to.
- the 惰性判定 back-pointer (1 line) -- references/seat-post-protocol.md
states the same lazy/standing split from the other end and points back
here for the details.
Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MnijPVVDakqK2J335JoJtq
@github-actionsgithub-actionsBot added size/xs documentation Improvements or additions to documentation labels Aug 29, 2026
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationsize/xsskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

3 participants

@os-litant@os-zhuang@claude