skills(pm-dispatch): the Thread-read: claim field with its H50 patrol row, and the carried-assertion rule - #16597
Merged
Conversation
…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
…d to Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018dxq7YqsLDMeZDZ5AzsgJX
Collaborator
Author
维护者速读(终稿 · skills 席,2026-09-07T12:0xZ)
Generated by Claude Code |
This was referenced Sep 7, 2026
os-zhuang
approved these changes
Sep 7, 2026
os-zhuang
marked this pull request as ready for review
September 7, 2026 12:05
os-zhuang
enabled auto-merge
September 7, 2026 12:05
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
This was referenced Sep 7, 2026
This was referenced Sep 7, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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 betweenClause-②: yes | noandSerial constraints cleared:(the latter stays the template's last line, as the 认领 section requires). Its key isThread-read:and its value is the id of the newest comment on the card at the moment the claim is written, or the literalnoneon 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, theClaim:first-line criterion untouched.scripts/pm/check-half-states.mjs, new family H50 (report-only,stateband): for every openpm:dispatchedcard, the newestClaim:(H47'slatestMarkedCommentresolution) stamped at or afterTHREAD_READ_FIELD_SINCEmust carry aThread-read:line whose value equals the id of the comment immediately before the claim in thread order (nonewhen 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 ornone, one pair of backticks tolerated; a hashed, prosed or capitalised value is reported as the text it is, theClause-②: YESposture). Unreadable claim stamp or unreadable predecessor id: the row DECLINES rather than accuses.The cutoff
THREAD_READ_FIELD_SINCEis2026-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
commentRowsForfetches 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 forpm:dispatchedcards, page by page toH50_COMMENT_PAGE_CEILING(H48's shape, same ceiling), and lands the longer thread incommentCachefor 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 rideSWEEP_COUNT_KEYS; the clause has itsSUMMARY_CLAUSE_ANCHORSentry.Self-test: 2636 → 2716 cases (+80), including the five ruled cases — match, mismatch, missing field,
noneon 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.
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 isreferences/review-checklist.md:67-68..claude/agents/os-dev.md:72「issue 正文是线索,不是规格。」) and, PM-side, at L437 「每条工作项写进派发令时都是 dev 首先证伪的前提。」 and L528 「派发词 ⛔ 默认不整段粘贴 issue 正文:让 dev 自己读全文与全部评论并自查正文完整性。」.Fold candidates rejected because
references/core-rules.mdmirrors 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 (md522f2339f0acb64cdb50c7adc9db681c3),check:skill-frame-syncgreen.Verification (readings, with the tree they were taken on)
Gates on head
6e652831d(the two card commits; the two pin commits ending atb6ae89aaachange one literal and its comment incheck-half-states.mjs, and the re-runs listed last were taken on it):node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstackderived 44 families from the merge-base changeset; every command run with its exit captured to a file before any pipe;--ranverdict: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-expressionsexited 3 (PREREQUISITE NOT MET: formula/lint unbuilt — NOT MEASURED), then exited 0 afterturbo run build --filter=@objectstack/formula --filter=@objectstack/lintunder the verify lock (✓ … 22 record-scoped formula example(s) across 434 files … judged clean).bash scripts/pm/os-verify-lock.sh -c "pnpm lint"(slotissue-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.mjswith 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 nopnpm check:self-test-wiredalias — 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.b6ae89aaa: self-test 2716 ✓, eslint oncheck-half-states.mjs✓, ratchet/id-lint/frame-sync ✓, nul-bytes ✓,--ran44/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):merge-tree --write-tree --name-only origin/main HEADwithorigin/main=7092d63e4, HEAD =6e652831d: clean (exit 0, tree504979a3).4d3194ba74againstorigin/main7092d63e4: exit 1,CONFLICT (content): .claude/skills/pm-dispatch/SKILL.md(core-rules.mdauto-merged) — dirty against main on its own, as the claim recorded; not a landing condition.6e652831dvs4d3194ba74: exit 1, the same SKILL.md conflict — whichever lands second re-folds, per the chain-head claim.origin/mainadvanced from the branch baseffca0df9to7092d63e4(one commit,packages/clientonly) 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.
验收备注
commentRowsForread also bounds H33/H20/H27/H37/H47/H49 on threads of 100+ comments; this PR completes the walk for thepm:dispatchedpopulation only. 承接者:无 (no open PR touchescheck-half-states.mjs).维护者速读(草稿)
改了什么: 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