Skip to content

skills(pm-dispatch): the Thread-read: claim field with its H50 patrol row, and the carried-assertion rule - #16597

Merged
os-musk merged 5 commits into
mainfrom
claude/issue-16377-claim-thread-read-field
Sep 7, 2026
Merged

skills(pm-dispatch): the Thread-read: claim field with its H50 patrol row, and the carried-assertion rule#16597
os-musk merged 5 commits into
mainfrom
claude/issue-16377-claim-thread-read-field

Conversation

@os-musk

@os-musk os-musk commented Sep 7, 2026

Copy link
Copy Markdown
Collaborator

Fixes #16377
Fixes #16197

Flight B of the skills lane's PM loop round 1 (seat ruling 5569655227 on the chain head; grading 5569743968 on the member). One PR, two cards, one commit each, plus two one-line pin commits (the literal, then its comment). Governed: the diff touches .claude/skills/pm-dispatch/SKILL.md, so this PR stays a draft for a human merge (skip-changeset: nothing published moves).

Card 1 — the Thread-read: claim field and its report-only patrol row (H50)

.claude/skills/pm-dispatch/SKILL.md, 模板与表 (L809): the claim template gains one line between Clause-②: yes | no and Serial constraints cleared: (the latter stays the template's last line, as the 认领 section requires). Its key is Thread-read: and its value is the id of the newest comment on the card at the moment the claim is written, or the literal none on an empty thread. A PM cannot fill it without fetching the thread's last page — that is the whole mechanism. No new label, no second spelling, the Claim: first-line criterion untouched.

scripts/pm/check-half-states.mjs, new family H50 (report-only, state band): for every open pm:dispatched card, the newest Claim: (H47's latestMarkedComment resolution) stamped at or after THREAD_READ_FIELD_SINCE must carry a Thread-read: line whose value equals the id of the comment immediately before the claim in thread order (none when the claim opened the thread). A missing field or a different value is one row carrying the claim's id, the id it named and the id actually there. A claim stamped before the cutoff is never judged. The value is read strictly (a bare id or none, one pair of backticks tolerated; a hashed, prosed or capitalised value is reported as the text it is, the Clause-②: YES posture). Unreadable claim stamp or unreadable predecessor id: the row DECLINES rather than accuses.

The cutoff THREAD_READ_FIELD_SINCE is 2026-09-07T11:55:00Z — the day this PR opened, pinned to a minute of that day after the last claim written under the old template and before the PR opened (the ruling names the date; the minute is a refinement on that date, so the PM's own claims on both cards written at 11:06Z/11:11Z today predate the field exactly as older claims do; flipping it to the bare date is a one-token change if the seat prefers the literal reading).

A PM mechanism assumption falsified in part (B2). The sweep does read comments per card, but commentRowsFor fetches ONLY the first page (per_page=100, no walk) — H2's deliberate trade, stated at its call site. This row's question is about the LAST page by construction, so the dispatch-liveness loop now completes a FULL first page to the thread's end for pm:dispatched cards, page by page to H50_COMMENT_PAGE_CEILING (H48's shape, same ceiling), and lands the longer thread in commentCache for every later reader (H33/H20/H27 in the same iteration, H37/H47/H49 after). Cost change: zero extra requests for a card whose first page is short; for a card with 100 or more comments, up to four extra pages; a walk still full at the ceiling leaves the card UNJUDGED for this row and the summary clause prints both the truncated count and the pages actually bought on the run (Thread-read fields (H50): J of C …). Four count keys ride SWEEP_COUNT_KEYS; the clause has its SUMMARY_CLAUSE_ANCHORS entry.

Self-test: 2636 → 2716 cases (+80), including the five ruled cases — match, mismatch, missing field, none on an empty thread, legacy claim before the cutoff (no row) — plus the reader's decoration tolerance and strictness, thread-order recency, population, the three input states, adjacency with H33/H2, and the registry/band/counter/clause pins the file requires of every family.

Card 2 — a carried count, zero or file face is re-measured or marked unverified

SKILL.md, 派发 (L542), directly under 「派发令里关于代码的危害断言必须有读数(点名 call site / 路径 / 迁移)。」:

搬自任何工件(含己文)本轮未亲测计数/零命中/文件面:重测或注「未验证」点名来源。

The line is 115 bytes against the ratchet's 120-byte per-line budget (the first draft at 191 bytes was refused by that rule, so the enumeration of source artifacts was compressed to 「任何工件(含己文)」 — any artifact, the seat's own earlier prose included — which is the ruling's content). The second line the grading offered (two stop conditions in one brief is a defect) is NOT landed: no third fold pays for it; recorded here as 未落.

The two folds — SKILL.md stays at 811/811

Each added line is paid by deleting one restating line in the same file; content survives elsewhere, quoted verbatim below.

  1. (paid for the template line) 复核, deleted: 「证伪是好运行:premise_still_valid: false 是再分诊输入;dev 纠正 PM 当众认。」 Its three clauses survive at L775 报告契约 「premise_still_valid: false + pr: null 是合法终报,当再分诊输入复核,永不当失败派发。」 (the core-rule twin, references/core-rules.md:149), L461 候选与批次 「该假设以机制假设身份进派发令,被证伪就在同一张卡公开更正。」, and L178 平台读数纪律 「sweep 晋级与立卡的前提要对此刻的 main;dev 带证据的零实现停手是好产出,不当返工计。」; the review-side detail is references/review-checklist.md:67-68.
  2. (paid for the 派发 rule) 派发, deleted: 「前提先行写明:issue 正文是线索不是规格。」 — an unconditional clause the same section forbids copying into a brief (L533 「标准非协商条款 ⛔ 不抄进派发词…os-dev.md 已载通用段砍掉。」, L535 「无条件条款只住角色文件…」). Its content survives as the dev's own rule 6 (.claude/agents/os-dev.md:72 「issue 正文是线索,不是规格。」) and, PM-side, at L437 「每条工作项写进派发令时都是 dev 首先证伪的前提。」 and L528 「派发词 ⛔ 默认不整段粘贴 issue 正文:让 dev 自己读全文与全部评论并自查正文完整性。」.

Fold candidates rejected because references/core-rules.md mirrors them (核心条款是本文的子集, so deleting the SKILL.md twin would need a same-PR core-rules edit outside this flight's file surface): 「45 分钟是发探针的门槛,⛔ 不是判死的门槛。」 (core-rules:119), 「档位逐次派发显式传参,永不省略。」 (core-rules:113), the 「发现分诊轮:finding 恒 = 待首次定级…」 line (core-rules:37).

Line budget: SKILL.md is 811 lines (ceiling 811; headroom 0); widest table row is 342 bytes (pin 342; headroom 0); the decision-frame block (now L734–752, was L735–753) is byte-identical (md5 22f2339f0acb64cdb50c7adc9db681c3), check:skill-frame-sync green.

Verification (readings, with the tree they were taken on)

Gates on head 6e652831d (the two card commits; the two pin commits ending at b6ae89aaa change one literal and its comment in check-half-states.mjs, and the re-runs listed last were taken on it):

  • node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack derived 44 families from the merge-base changeset; every command run with its exit captured to a file before any pipe; --ran verdict: 44 derived famil(ies) accounted for — 44 run, 0 NOT-MEASURED. 43 exited 0 on the first pass; pnpm --filter @objectstack/lint run check:doc-formula-expressions exited 3 (PREREQUISITE NOT MET: formula/lint unbuilt — NOT MEASURED), then exited 0 after turbo run build --filter=@objectstack/formula --filter=@objectstack/lint under the verify lock (✓ … 22 record-scoped formula example(s) across 434 files … judged clean).
  • bash scripts/pm/os-verify-lock.sh -c "pnpm lint" (slot issue-16377): VERDICT command-exit 0 · held the lock 114s · waited 0s — the full repo-wide eslint, not a narrowing.
  • node scripts/pm/check-half-states.mjs --self-test: ✓ check-half-states self-test: 2716 cases pass. (2636 before).
  • pnpm check:pm-skill-ratchet, pnpm check:pm-skill-id-lint (26 file(s) clean), pnpm check:skill-frame-sync (2 copies … structurally isomorphic), pnpm check:nul-bytes (scanned 8166 text file(s) … no raw ASCII control bytes), node scripts/check-self-test-wired.mjs with and without --self-test (every one of the 186 script(s) CI runs that ship a --self-test has that self-test run by CI; note there is no pnpm check:self-test-wired alias — pnpm answers 254 "no script" to that spelling): all green.
  • node scripts/pm/check-governed-merges.mjs --test .claude/skills/pm-dispatch/SKILL.md scripts/pm/check-half-states.mjs: exit 3, .claude/** ×1 — .claude/skills/pm-dispatch/SKILL.md, paths not on the register: scripts/pm/check-half-states.mjs — governed whole, as expected.
  • Re-run on the final head b6ae89aaa: self-test 2716 ✓, eslint on check-half-states.mjs ✓, ratchet/id-lint/frame-sync ✓, nul-bytes ✓, --ran 44/44 ✓, self-test-wired both legs ✓.

Serial-constraint probe, from a driver-less bare clone (git --git-dir=PROBE.git config --get merge.os-regen.driver → exit 1, unset):

  • A. merge-tree --write-tree --name-only origin/main HEAD with origin/main = 7092d63e4, HEAD = 6e652831d: clean (exit 0, tree 504979a3).
  • B. the same probe for devx draft PR docs(pm-dispatch): read the verify-lock queue depth before each dispatch and hold at depth ≥ 2 (#14944 Q1 B) #16271 head 4d3194ba74 against origin/main 7092d63e4: exit 1, CONFLICT (content): .claude/skills/pm-dispatch/SKILL.md (core-rules.md auto-merged) — dirty against main on its own, as the claim recorded; not a landing condition.
  • C. HEAD 6e652831d vs 4d3194ba74: exit 1, the same SKILL.md conflict — whichever lands second re-folds, per the chain-head claim.

origin/main advanced from the branch base ffca0df9 to 7092d63e4 (one commit, packages/client only) during the run; not merged into this branch (probe A is clean and the incoming commit shares no file with this diff).

Four-axis notes on the two choices this flight made

Cutoff resolution (a minute of the opening day rather than its midnight): 实际业务需求 — the claims that exist today without the field were written before the field existed, hours earlier the same day; flagging them would put two false rows on the anchor at the first sweep. 项目长远合理性 — a cutoff is an instant; a date is an instant with coarser resolution, same shape. 防 AI 犯错 — an instant that predates every field-less claim removes the one case where a correct legacy claim reads as a defect. 创业阶段不扩散 — one literal, no second mechanism.

Completing the walk rather than declining on a full first page: 实际业务需求 — the field's whole meaning is the LAST page; a first-page-only read would judge the wrong claim on exactly the long threads where a late ruling is most likely. 项目长远合理性 — H48 already established the page-ceiling walk for PR threads; reusing its shape keeps one discipline. 防 AI 犯错 — a truncated walk is named UNJUDGED and counted, never read as clean. 创业阶段不扩散 — bounded by the same ceiling constant, zero cost on short threads, pages bought printed per run.

验收备注

  • noted, not filed: the first-page-only commentRowsFor read also bounds H33/H20/H27/H37/H47/H49 on threads of 100+ comments; this PR completes the walk for the pm:dispatched population only. 承接者:无 (no open PR touches check-half-states.mjs).
  • noted, not filed: the ratchet's 120-byte per-line budget is not mentioned in SKILL.md's 机械守卫索引 row for the ratchet (only the line count and re-wrap rule are); the gate's own message is complete. 承接者:无.

维护者速读(草稿)

改了什么: PM 认领评论模板多了一行 Thread-read:,要求填写认领那一刻卡片上最新一条评论的 id(空线程填 none);半状态巡查脚本新增 H50 一族,每轮核对每张在飞卡最新认领评论里这个 id 是否等于紧邻其前的那条评论,不等或缺失就在巡查锚上出一行(只报告,不改标签)。同时派发规则多了一条:席位从别的工件(含自己早先写的)搬来、本轮没有亲测的计数、零命中、文件面,要么重测,要么写明「未验证」并点名来源。技能文件行数不变(811/811),靠删掉两句复述句付账。

为什么改: 六天内三个席位都从卡片正文直接派发、没读评论——而评论里正是分诊定级、先前裁决和其它席位读数,是覆盖正文的内容。写在规则里的提醒已经两次失效,所以这次不改措辞,改成一个能被机器核对的字段。第二条规则对应同一班次里四起「把别人散文里的数字当成测量值」的事故。

风险与代价(含回滚): 巡查族只读不写,最坏情况是巡查锚上多几行误报;字段落地日期之前的旧认领不会被判。脚本对评论超过 100 条的在飞卡多买最多四页评论(短线程零成本,买了几页写在汇总行上)。回滚 = revert 本 PR 的四个 commit,无数据、无发布件。

席位意见: (留空,由复核席填写)

你要做的: 一个动作:确认后人工合并本 PR(受管面,不进队列)。

🤖 Generated with Claude Code

https://claude.ai/code/session_018dxq7YqsLDMeZDZ5AzsgJX


Generated by Claude Code

…l row (H50)

The claim template gains one line a seat cannot fill without fetching the
card's thread to its last page: the id of the newest comment at the moment
the claim is written, or `none`. `check-half-states.mjs` gains H50, which
holds the newest `Claim:` on every open `pm:dispatched` card to it — a
missing field or a value other than the id of the comment immediately before
the claim is a report-only row carrying the claim id, the id named and the
id actually there; claims stamped before `THREAD_READ_FIELD_SINCE` are never
judged. The dispatch-liveness loop now completes a FULL first comment page
to the thread's end (H48's ceiling shape) for exactly that population, and
the summary line prints the pages bought and the threads left UNJUDGED.

SKILL.md stays at 811 lines: the template line is paid by folding the 复核
restatement 「证伪是好运行…」, whose three clauses survive in 报告契约,
候选与批次 and 平台读数纪律.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018dxq7YqsLDMeZDZ5AzsgJX
…d or marked unverified with its source named

One rule line in the 派发 section beside 「派发令里关于代码的危害断言必须有读数」:
a count, a zero hit or a file face carried from any artifact — a card, a
sibling PR, a prior ruling, the seat's own earlier prose — that the seat did
not measure this round is re-measured, or written as unverified with the
source artifact named. Four measured instances in one shift passed review
gates as "readings" and were caught only by a dev re-deriving them.

SKILL.md stays at 811 lines: the line is paid by folding 「前提先行写明:issue
正文是线索不是规格。」, an unconditional clause the same section forbids
copying into a dispatch brief, and whose content survives in the dev-agent
definition (rule 6) and in 「每条工作项写进派发令时都是 dev 首先证伪的前提」.
The two-stop-conditions line is NOT landed: no third fold pays for it.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018dxq7YqsLDMeZDZ5AzsgJX
…at opens the PR

The cutoff literal was written ahead of the clock; it now reads the minute of
this push, on the day the PR opens, and its comment says so.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018dxq7YqsLDMeZDZ5AzsgJX

os-musk commented Sep 7, 2026

Copy link
Copy Markdown
Collaborator Author

维护者速读(终稿 · skills 席,2026-09-07T12:0xZ)

  • 改了什么:① PM 认领评论模板多一行 Thread-read: —— 填写认领那一刻卡片上最新一条评论的 id(空线程填 none);半状态巡查脚本新增 H50 一族:对每张在飞(pm:dispatched)卡,最新认领评论里这个 id 必须等于紧邻其前那条评论的 id,缺失或不等就在巡查锚上出一行(只报告、不改标签、不拦任何东西);2026-09-07T11:55Z 之前的旧认领一律不判。② 派发规则多一条:席位从别的工件(含自己早先的散文)搬来、本轮没亲测的计数 / 零命中 / 文件面,要么重测,要么写明「未验证」并点名来源。SKILL.md 行数不变(811/811),靠删掉两句复述句付账;巡查脚本 +391 行,自测 2636 → 2716 例。
  • 为什么改:六天里三个席位都从卡片正文直接派发、没读评论 —— 评论里正是分诊定级、先前裁决和别席读数,是覆盖正文的内容;写两次的提醒失效了两次,所以不再改措辞,改成一个机器能核对的字段(填不出这个 id 就说明没翻到最后一页)。第二条对应同一班次四起「把别人散文里的数字当测量值」的事故。
  • 风险与代价(含回滚):巡查族只读不写,最坏是巡查锚多几行误报;脚本对评论超过 100 条的在飞卡最多多买四页评论(短线程零成本,买了几页写在汇总行上)。所有席位从下一次认领起要多写一行。回滚 = revert 四个 commit,零数据、零发布件。
  • 席位意见:席位在 head b6ae89aa 的分离副本上亲跑了自测(2716 通过)、行数棘轮(811/811、表行 342)、id-lint、frame-sync 与受管判定(exit 3);逐行读了 SKILL.md 的 2 进 2 出,两句被删的复述内容分别在 528/540 行与 775 行(以及 review-checklist 的「dev 纠正 PM 要当众认」)幸存;读了 H50 的谓词与 80 例自测,判据与裁决一致(匹配 / 不匹配 / 缺失 / 空线程 none / 截止前旧认领不判),对 origin/main de0bcdd4 的 merge-tree 干净。截止时刻取 11:55Z 而非当日零点是对的:今天上午的旧模板认领不该被判。CI 33 项 12:01Z 无红,八项仍在跑。这是对协议的一次真实变更(所有席位都要填这一行),按否决窗口执行 —— 你若不要这个字段,一句话本席回滚。建议合并。
  • 你要做的:人工合并本 draft PR(受管面不进合并队列);或者一句话否决。

Generated by Claude Code

@os-zhuang
os-zhuang marked this pull request as ready for review September 7, 2026 12:05
@os-zhuang
os-zhuang enabled auto-merge September 7, 2026 12:05
@os-zhuang
os-zhuang added this pull request to the merge queue Sep 7, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to a conflict with the base branch Sep 7, 2026
…e-fold SKILL.md after #16271

One conflict, .claude/skills/pm-dispatch/SKILL.md: #16271 joined 拒收用例 and
过滤/谓词语义 on one line where this branch had folded the neighbouring
「前提先行写明:issue 正文是线索不是规格。」. Resolution keeps both: main's
joined line stays, the fold stays. Both sides' content survives — #16271's
four depth-hold lines, its priority:p0 row edit and its four same-file
merges; this branch's Thread-read template line, its carried-assertion rule
and its two folds. SKILL.md stays at 811 lines; references/core-rules.md is
main's copy untouched.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018dxq7YqsLDMeZDZ5AzsgJX
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation needs-user-decision size/m skip-changeset PR has no user-facing published change; bypasses the changeset gate

Projects

None yet

3 participants