Skip to content

docs(pm-dispatch): card-thread backend (mode:thread), coordinator scheduling and per-card dispatch effort - #25214

Merged
objectstack-fleet[bot] merged 9 commits into
mainfrom
claude/project-thread-4nzwyi
Oct 22, 2026
Merged

objectstack-fleet[bot] merged 9 commits into
mainfrom
claude/project-thread-4nzwyi

Conversation

@objectstack-fleet

@objectstack-fleet objectstack-fleet Bot commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor

Requested by Bill · project thread

Fixes #25185

Clause-②: no
Metadata-protocol: none

What changed

Four .claude/** files, 29 insertions and 26 deletions by GitHub's count, no code.

  1. A third dispatch backend, mode:thread — SKILL.md args table (mode: row and the batch: row, which now counts card threads), the claim template's Container & model: line, os-dev.md's "GitHub is the report's source of truth under every mode" line, and a new section 〈卡线程(mode:thread)〉 in references/dispatch-runbook.md beside the mode:cloud section. The rules it carries, each from the maintainer's words quoted on the card:
    • A seat whose session is a project thread dispatches M and up, priority:p1 and security cards as one thread per card; S-class mechanical cards stay an in-seat subagent (a thread re-clones and re-reads the skill first); a card under the disclosure ruling (record 5323310017) stays in-seat too; a card thread counts against batch.
    • The project's coordinator schedules card threads across every seat, p1 first, under a project-wide cap equal to the sum of the seats' batch terms; seats hand it candidates at any time with priority, order file and suggested effort, and tell it when a thread hands back or its PR merges.
    • The seat keeps the claim, the assignee, the order, the contract review, ACCEPT and landing; the thread implements, opens the draft PR and drives CI. The order lives in the project's shared folder (/mnt/project-files/, one dispatch-N.md per card under the seat's folder). Claim mechanics changed after the first contract review (record 6341183860): the thread's first act is to report its designated push branch to the seat and wait; the seat writes the assignee and pm:dispatched, then posts the Claim carrying that Branch:, in AGENTS.md's order; the thread starts only after that, posts no claim and never writes the assignee. claude/issue-N-slug remains the branch convention; a project-thread session can push only its own designated branch (measured: the session's harness names that branch and forbids any other), so the claim records that branch as the platform exception. The coordinator sets a thread's model and effort only on the maintainer's explicit word, so the seat attaches that message.
    • Environment notes, one line each: the worktree is still built (the main-checkout hooks block edits in the primary checkout); the repo's .claude/agents types did not load in a project thread (measured), so the thread reads os-dev.md; container restarts kill local background loops, so the seat waits on server-side signals.
  2. Dispatch effort by difficulty — two lines in references/execution-duties.md 〈派发〉 and the effort: field in the claim template: effort is chosen per card beside the model tier, written into the claim and the order and passed explicitly, never left unset. Grading as the card proposed, unchanged by measurement: S mechanical medium; M high (the default); L/XL, security, p1, the contract review and four-axis analysis xhigh; max only when the maintainer names it. The card's Container & model: reader (readContainerModelLine) still reads the model: slot with the new field present; this PR's own claim (comment 6335635315) carries the new shape and passed post-stamped.

The maintainer's words, verbatim and untranslated, as the card quotes them: 「你能识别到在项目的环境下工作吗?此时就每张卡开新线程。」 · 「立一张卡,修改 skills,包括派任务时要求根据任务的难度来选择 effort」 · 「还是需要你来总体调度,因为要优先派 p1」 · 「规则类的应该进仓库」 · on the S/M boundary 「同意」. The ruling-thread rule left this PR after the first contract review; it is card #25216.

How the line ratchet was paid

check:pm-skill-ratchet holds every file here at a shrink-only ceiling. The new text needed +17 lines in dispatch-runbook.md and +2 in execution-duties.md. The maintainer left the choice (「你自己决定 :抬上限 / 删旧内容 / 压缩」) and the spec seat preferred deletion, so no ceiling moved: both files land exactly at their ceilings (241 and 188) by deleting lines whose rule is already stated in another file of the same corpus. Reviewers, each deletion with the surviving home of its rule:

dispatch-runbook.md (16 deleted, 2 merged into 1):

  • 「种子与消费者注记在 ensure-pm-labels.sh」 → SKILL.md 〈机械守卫索引〉 names that script as the authority.
  • 「机械年龄告警在半状态巡查脚本」 → SKILL.md 〈机械守卫索引〉 check-half-states.mjs row.
  • 「⛔ 不设第二个标签区分维护者裁与座位定级」 → state-machine.md (the hold-comment line).
  • 「每批约定:≤5 张同族卡、同上下文逐张读」 → SKILL.md 〈入口与角色〉 「批 = …≤5 张同族卡」.
  • 「在飞认领照认领协议由原认领者跟完」 → seat-post-protocol.md (subtree reclaim) and SKILL.md 状态模型 「在飞卡跟到 MERGED」.
  • 「第三读数(…)出自车道盘点」 → seat-lifecycle.md 读数三.
  • 「机械半边:旗标由半状态巡查 report-only 浮出…」 → the same file's 〈落卡与裁决记录细则〉 「机械两旗 report-only,归半状态巡查」 line, kept.
  • 「终报以 issue 评论交付,带 os-dev-report 标记」 → os-dev.md lines 17–18.
  • 「生产侧条款在 os-dev 定义」 → a pointer with no rule of its own.
  • 「重放形态可以完全正常…monitor 按自己的 deadline 触发」 → os-dev.md 〈干净收尾〉 item 1; the identity triple that follows it is kept.
  • 「抢先翻 ready 会撞上 agent 的收尾推送,故先探活后翻」 → execution-duties.md 〈收集〉 「先探活后翻 ready」.
  • 「推分支 → 开 draft PR → 立即交报告的契约住 os-dev 定义」 → os-dev.md Definition of done; 「派发令只带增量」 → execution-duties.md 〈派发〉.
  • 「三分区各自的 dev 义务单源见 SKILL.md 与 os-dev 定义,派发词 ⛔ 不复述」 → execution-duties.md 「标准非协商条款 ⛔ 不抄进派发词」.
  • 「模型标识只禁内容工件…」 and 「豁免:.claude/agents/* frontmatter 的 model:」 → AGENTS.md (commit-message paragraph of Multi-agent discipline), os-dev.md 285–286 and its frontmatter comment, execution-duties.md 「解析顺序…以 os-dev 定义 frontmatter 注释为权威」.
  • 「⛔ 仓内任何文件不得另立第三份,check:skill-frame-sync 全树扫;os-dev 定义没带就停下索取」 → os-dev.md 356–357 and SKILL.md 〈机械守卫索引〉 check:skill-frame-sync row.
  • Merged: 「四轴框架块…整段现取现粘」 + 「该块自黑体句起、至推荐约束句止,整段逐字粘贴」 → one line carrying both bounds and the verbatim rule.

execution-duties.md (2 deleted):

  • 「每条工作项写进派发令时都是 dev 首先证伪的前提」 → os-dev.md rule 6 (the dev verifies every premise regardless), and the same section's 「标准非协商条款 ⛔ 不抄进派发词」 says not to restate it in the order.
  • 「云会话 SendMessage not-reachable 是设计非故障,⛔ 不复测」 → dispatch-runbook.md 〈云卡四课〉 「roster 不可达与 SendMessage 同裁,ListAgents 同列不到,⛔ 不复测」, kept.

Every line added or edited is at most 120 bytes (the ratchet's max-line rule); the four-axis frame was not touched (check:skill-frame-sync and check:skill-frame-freshness green).

Landing and the claim's model line

  • .claude/** is Tier S under AGENTS.md Prime Directive 14, not a human merge as the card's first sentence says: the owning seat lands this PR after a ## Contract review record for its head with Served-tier: CONTRACT_REVIEW_TIER and a PASS verdict, plus all-green checks. The PR stays a draft until then.
  • The claim's Container & model: line says model: default; dispatch-gates --tier prints MANDATORY CONTRACT_REVIEW_TIER for SKILL.md and os-dev.md. The seat corrected this mid-card: the maintainer switched this thread to that tier (「切换到 fable」, 08:08Z) and the whole diff was re-read at it before this PR opened; that re-read found and fixed one contradiction in the mode: row (S+M ⇒ subagent against M+ ⇒ thread; now 「席位是项目线程时 M 及以上、p1、security 一律 thread」).

Open questions for the contract review (settled in round 2)

  1. AGENTS.md's 「the dispatch posts the Claim:」: settled. The seat posts the claim and writes the assignee; the thread posts neither. This card's own round-1 claim and assignee were written by the thread under the round-1 order, before this rule existed; they stand as the record.
  2. SKILL.md 红线 「⛔ GitHub 之外永不维护任何跟踪状态」: a card that waits for a coordinator slot is not yet claimed (the claim needs the thread's branch), so its only GitHub trace is its pm:queue label and priority. The coordinator's queue is a view derived from those labels and rebuildable from GitHub at any time; the order files are inputs, not state. Once a thread opens, the card carries assignee, pm:dispatched and the Claim like any other dispatch.
  3. The ruling-thread line: dropped from this PR; card pm-dispatch: inside a Claude Code project, a card thread's needs_decision fork goes to a separate ruling thread at the contract-review tier, which rules when confident and sends the maintainer a decision card otherwise (maintainer's word 2026-10-22) #25216 carries the maintainer's word and has to be reconciled with 「总监席是唯一裁决者」 there.
  4. The branch name: claude/issue-N-slug stays the convention; the designated thread branch is recorded as the measured platform exception. The Duplicate Fix Guard is advisory. Whether AGENTS.md §2 itself should name the exception is a Tier H question the seat has taken to the maintainer; this PR touches no Tier H file.

Gates

Round 2, head e704856: dispatch-gates --commands --repo objectstack-ai/objectstack derived the same 22 families, each run with its exit code captured before any pipe, all 22 exit 0; --ran 22/22, 0 NOT-MEASURED. check:skill-frame-freshness and check:pm-skill-ratchet exit 0 (dispatch-runbook.md 240/241, execution-duties.md 188/188, SKILL.md 319/319, os-dev.md 404/404). Round 1 at b301b37: the same 22, all 0; check:doc-formula-expressions first exited 3 (unbuilt @objectstack/lint), rebuilt under the verify lock and re-run to 0. CI's remaining families are the PR's check-runs. No published package moved (.claude/** is a fast-track non-published path), so skip-changeset rides this PR's create.

维护者速读(草稿)

改了什么: pm-dispatch 技能加了第三种派发后端 mode:thread:席位在项目线程里跑时,M 及以上、p1、security 的卡每张开一个线程,由 coordinator 跨席位按 p1 优先统一调度,总并发 = 各席 batch 之和;S 级机械小改仍用席内子 agent。派单按难度选 effort(S medium、M high、L/XL/p1/security/契约复核/四轴 xhigh、max 只凭你点名)。认领与 assignee 仍由席位写,线程先报分支再开工。行数上限没动,用删掉 18 条已在别处写明的旧规则抵账。

为什么改: 你 10-22 在项目里定的这几条规则(「规则类的应该进仓库」)。

风险与代价(含回滚): 纯规则文本,不碰代码与门禁;回滚即 revert 本 PR。AGENTS.md §2 的分支约定是否要写明项目线程的例外,属 H 档,席位已另报给你。

席位意见:

你要做的: 无;.claude/** 是 Tier S,席位做完契约复核后自行落地。

Acceptance notes

  • The dispatch order's claim template carried Thread-read: none (no comments yet); post-stamped refuses that spelling (H50 compares it for equality against one id or none). The seat has already corrected its template; noted here, not filed.
  • The dispatch order said the PR body starts with the attribution block linking the seat thread; the session's own attribution requirement names this card thread. This body follows the session's requirement; the deviation from the order is reported in the os-dev-report.
  • The attribution block's first line is an HTML comment the session requires as the body's first line; os-dev.md 〈干净收尾〉 forbids HTML comments in GitHub text. Measured on an earlier card thread's PR, the relay read-back keeps it byte for byte. Reported as a deviation, not hidden.

Generated by Claude Code

…patch effort

A seat whose session is a project thread dispatches each card as its own
thread; the dispatch effort is chosen per card by difficulty, beside the
model tier, in the claim's Container & model line and the dispatch order.

Claude-Session: https://claude.ai/code/session_01NVBPkGXNnJayvXnCjcXpFb
Co-authored-by: Claude <noreply@anthropic.com>
… the coordinator

Claude-Session: https://claude.ai/code/session_01NVBPkGXNnJayvXnCjcXpFb
Co-authored-by: Claude <noreply@anthropic.com>
…nd security go to a thread

Claude-Session: https://claude.ai/code/session_01NVBPkGXNnJayvXnCjcXpFb
Co-authored-by: Claude <noreply@anthropic.com>
…review-tier ruling thread

Claude-Session: https://claude.ai/code/session_01NVBPkGXNnJayvXnCjcXpFb
Co-authored-by: Claude <noreply@anthropic.com>
…eady stated elsewhere

dispatch-runbook.md: 16 lines whose rule lives in SKILL.md, os-dev.md,
state-machine.md, seat-lifecycle.md, seat-post-protocol.md or
execution-duties.md, plus two frame-paste lines merged into one.
execution-duties.md: two lines already stated by os-dev.md rule 6 and
the runbook's cloud section. Both files land at their ceilings.

Claude-Session: https://claude.ai/code/session_01NVBPkGXNnJayvXnCjcXpFb
Co-authored-by: Claude <noreply@anthropic.com>
@objectstack-fleet objectstack-fleet Bot added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Oct 22, 2026
@github-actions github-actions Bot added size/s documentation Improvements or additions to documentation labels Oct 22, 2026
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: b301b37e05bd1798d1e7825938f12d93abafbaee
Local-runs: none
Scope: .claude/agents/os-dev.md, .claude/skills/pm-dispatch/SKILL.md, .claude/skills/pm-dispatch/references/dispatch-runbook.md, .claude/skills/pm-dispatch/references/execution-duties.md + AGENTS.md, .claude/skills/pm-dispatch/references/state-machine.md, .claude/skills/pm-dispatch/references/seat-post-protocol.md, .claude/skills/pm-dispatch/references/seat-lifecycle.md, .claude/skills/pm-dispatch/references/triage-duties.md, .claude/skills/pm-dispatch/references/lanes/director.md, scripts/pm/check-skill-line-ratchet.mjs, scripts/pm/dispatch-gates.mjs (readContainerModelLine), scripts/pm/post-stamped.mjs (H50 Thread-read), scripts/check-closing-target-claim.mjs with .github/workflows/closing-target-claim-guard.yml, scripts/pm/check-governed-merges.mjs (GOVERNED_SURFACES), .github/workflows/duplicate-fix-guard.yml, scripts/check-commit-card-trailers.mjs

Inputs: card #25185 body and all three comments (claim 6335635315, the skills seat's waiting note 6339578152, the dev's os-dev-report 6340929602); PR #25214 body, file list and the net diff against main at the head above (4 files, 29 insertions, 26 deletions by GitHub's count); the 40 check-runs on that head, read at 2026-10-22T12:50Z: every one success or an expected skipped, none pending, none red. Read-only throughout: diff via the REST diff media type, blobs via git show on the fetched head, no checkout, no gate re-run.

① Derived judgments

Card acceptance criteria. Item 1 (recognise the project environment; mode:thread beside mode:subagent and mode:cloud; the seat keeps claim text, order, contract review, ACCEPT and landing; the thread implements, opens the draft PR and drives CI; disclosure-ruling cards stay in-seat; a card thread counts against batch; S/M boundary; coordinator scheduling; order file in the project's shared folder; hand-back in one message, thread stays open for FAIL items) — met in text, see the runbook section 〈卡线程(mode:thread)〉 lines 131–147, the SKILL.md mode: and batch: rows, and os-dev.md line 325. Item 2 (effort by difficulty as a field of its own beside the model tier, in the claim's Container & model: line and the order; S medium, M high, L/XL, security, p1, the contract review and four-axis analysis xhigh, max on the maintainer's word) — met verbatim: SKILL.md template line 290 and execution-duties.md lines 118–119. Three of item 1's mechanics are where the FAIL items below sit (claim poster, atomic pair, branch name), and the ruling-thread rule is beyond the card.

Rule-by-rule, right unless marked:

  • SKILL.md mode: row — 「席位是项目线程时 M 及以上、p1、security 一律 thread」: right, it says what the maintainer's 「同意」 says. Note, not a defect: the row and the card leave an S-mechanical p1 card ambiguous (「S 级机械卡留席内」 vs 「p1 一律 thread」); the seat reads p1 as the override, which is the safer reading. execution-duties.md lines 144–146 (S+M ⇒ subagent; build-heavy ⇒ cloud) carry no project-thread qualifier and are read under the SKILL.md row's.
  • SKILL.md batch: row counts card threads: right, matches the card.
  • Claim template effort: field and execution-duties.md 118–119: right. readContainerModelLine (dispatch-gates.mjs line 12236) reads the first model: token on the line; mode: does not match model, the trailing effort: is not consulted, and this PR's own claim 6335635315 carrying the new shape passed post-stamped. CONTAINER_MODEL_KEY_LINE still matches.
  • Runbook 131–133 (project-thread recognition, S stays in-seat with the stated cost reason, disclosure cards stay in-seat, threads count against batch): right.
  • Runbook 134–138 (coordinator schedules across seats, p1 first, cap = sum of seat batch terms, seats hand candidates at any time, seat frees the slot, maintainer's message attached for model and effort): right against the card. See ③ on the no-state-outside-GitHub line: right only once FAIL 1 is fixed.
  • Runbook 139 (seat keeps claim text, order, contract review, ACCEPT, landing; thread implements): right.
  • Runbook 140 (order at /mnt/project-files/SEAT/dispatch-N.md because a thread cannot read the seat's scratchpad): right, matches the card.
  • Runbook 141–142 (claim posted by the thread; 「原子对两笔都由线程执行,先认领后标签」): wrong — FAIL 1. Line 134 makes the card thread the dev (「卡线程即 dev」). AGENTS.md (Multi-agent discipline, 「Claim the issue BEFORE you write any code」) says the dispatch sets the assignee (step 1) and posts the Claim: (step 2) on the dev's behalf, and that a dispatched executor 「⛔ never writes the card's assignee」; os-dev.md rule 2 (「卡 assignee 归 PM … 恒不写卡的 assignee」) and execution-duties.md line 60 (「卡 assignee 归 PM,dev 恒不写」) say the same, and this PR touches both files without reconciling either. Line 142 also reverses the standing order of the pair (execution-duties.md 64–66: assign + pm:dispatched first, claim second; line 65's 「step ① 之后获得 assignee 的直接弃出本批」 race depends on that order) without saying which order governs mode:thread. The dev's report confirms the thread did write the card's assignee on this very card. AGENTS.md wins over a skill file (AGENTS.md line 7; SKILL.md 优先级), so the skill cannot grant this.
  • Runbook 143 (「分支用线程的指定推送分支」): wrong — FAIL 2. AGENTS.md discipline §2 (「Name the branch after the issue it fixes: claude/issue-N-slug」), os-dev.md lines 26, 274 and the report contract's branch field (line 366), and the SKILL.md claim template's Branch: line all require the issue-named branch; this line directs a name they forbid, and nothing in the PR or the report measures that a card thread cannot push a branch of its own name. The premise behind line 141 (「席位开线程后才知道」 the branch) exists only because of this line.
  • Runbook 144 (hand-back message; thread stays open for FAIL): right.
  • Runbook 145–146 (a card thread's needs_decision goes to a coordinator-opened CONTRACT_REVIEW_TIER ruling thread that 「有把握的自裁、落裁决评论」 and sends a decision card only where unsure): wrong — FAIL 3. Not on the card: pm-dispatch: inside a Claude Code project, dispatch each card as its own thread, and choose the dispatch effort by the card's difficulty #25185's acceptance text has no ruling thread, and the maintainer's word the PR body quotes for it (「对于这种类似的问题…自己决定,不能决定的开决策卡」) is recorded nowhere on the card — lanes/director.md 「裁决只存在于本卡:聊天原话、台账行、他卡引述 ⛔ 都不是裁决」. As written it contradicts SKILL.md line 255 (「总监席是唯一裁决者:决策箱、代裁与一类自裁只出自本席,⛔ 无子代理无自述」) and the 红线 「唯一例外是已裁的代裁通道,不得宽于其置信门」: 「有把握」 is a wider gate than the delegated channel's.
  • Runbook 147 (container restarts kill local loops; wait on server-side signals): right, an environment reading stated as a rule.
  • execution-duties.md line 92 pointer to the runbook, and the 〈收集〉 line's 「各模式」: right.
  • os-dev.md line 325 (three modes, GitHub is the report's source of truth): right. The card's expected surface was 「os-dev.md where it assumes a subagent」; the places where it assumes the issue-named branch (lines 26, 274, 366) were left as they are, which is correct once FAIL 2 is fixed by keeping that name.

The 18 deletions, each verified against the head tree — every rule keeps a surviving home; none is a FAIL: ensure-pm-labels.sh → SKILL.md 机械守卫索引 row (line 297); mechanical age alert → SKILL.md check-half-states.mjs row (293), the script header being the authority per AGENTS.md; no second label → state-machine.md line 16; ≤5 same-family batch → SKILL.md line 68, and its 「常设授权,⛔ 不逐次请示」 half → triage-duties.md lines 19 and 116; in-flight claims followed by the original claimant → seat-post-protocol.md line 74 and seat-lifecycle.md line 29; reading three → seat-lifecycle.md line 10; mechanical half of the two flags → runbook line 83 kept plus 〈结论当轮执行〉; os-dev-report comment delivery → os-dev.md line 17; 「生产侧条款在 os-dev 定义」 was a pointer; replay can look normal → os-dev.md line 330; probe before ready → execution-duties.md line 172; push → draft PR → report, and 「派发令只带增量」 → os-dev.md lines 16–18, 61, 274 and execution-duties.md line 123; three-partition single source → execution-duties.md line 127 and os-dev.md lines 182–184; four-axis block two lines merged into runbook line 211 with both bounds and 「逐字」 kept, per-order fetch kept at line 212; no third copy, stop and ask → os-dev.md lines 356–357 and SKILL.md line 298; model identifier only in content artefacts → AGENTS.md commit-message paragraph and os-dev.md lines 285–286; frontmatter model: exemption → os-dev.md lines 12–13 (the gate named there); every work item is a premise to falsify → os-dev.md rule 6; cloud SendMessage not-reachable by design → runbook line 124.

Ratchet. CEILINGS in check-skill-line-ratchet.mjs: SKILL.md 319, dispatch-runbook.md 241, execution-duties.md 188, os-dev.md 404. Head counts 319 / 241 / 188 / 404; base counts 319 / 238 / 188 / 404. No ceiling moved and the script is not in the diff. Longest added line 120 bytes (the SKILL.md template line is 290 bytes, but it is a pre-existing line edited in place inside a fenced template, and the other two long lines are pre-existing table rows). Additions paid by deletion, not re-wrap; the one merge is a density fix that keeps content. Right.

PR body, non-blocking notes for the seat's 终稿: it says 「21 insertions and 25 deletions」; GitHub counts 29 / 26 (edited lines count on both sides). Two maintainer quotations in the body contain a model name; check-commit-card-trailers.mjs judges only the trailer pair and AGENTS.md exempts a verbatim maintainer ruling, so no gate reds, but the seat should keep those quotations as quotation blocks when it writes the record of review.

② Semver level

skip-changeset is right. The diff is four files under .claude/**, no package moves, Clause-②: no, Metadata-protocol: none declared line-initial in the body; Check Changeset is green on the label. The tier is CONTRACT_REVIEW_TIER because every path hits the Tier S register row claude-tree (GOVERNED_SURFACES, check-governed-merges.mjs line 1178); head and base repos are both objectstack-ai/objectstack, so this is a delivery, not a fork proposal.

③ Boundary flags

  1. AGENTS.md's 「dispatch posts the Claim」 vs a thread-posted claim — blocks this PR; the fix rides it, no Tier H line is owed. Option A as the dev states it is not available: the thread also wrote the assignee, which AGENTS.md forbids an executor in so many words, and the sentence is a rule, not prose. Option B is unnecessary once the branch is the seat's to name (flag 4): the order then names claude/issue-N-slug exactly as a subagent order does, the seat performs step ① (assign + pm:dispatched, drop pm:queue) and posts the claim itself before it asks the coordinator, with its own session id (SKILL.md: under one shared identity 「身份看分支」; the thread's own session id lands in the report's session field, os-dev.md line 368), and the thread does what AGENTS.md already asks of every executor: verify the newest Claim: names its branch, build the worktree on that branch, push it empty, post no second claim. Lines 141–142 are rewritten to that; the card itself left this 「for the PR to settle」.
  2. The coordinator queue vs 「⛔ GitHub 之外永不维护任何跟踪状态」 — blocks as written, cleared by the same fix. Under lines 141–142 a card handed to the coordinator and waiting for a slot has no GitHub trace at all: it is still pm:queue, unassigned, claimable by another seat (the skills seat's note on this card shows cross-seat interest), and a fresh seat session cannot recover the queue. The dev's reading A (「derived from pm:dispatched cards and their claims」) is true only when step ① and the claim precede the hand-over; then a waiting card is pm:dispatched + assignee + a Claim: naming mode:thread with no pushed branch yet, which is exactly the 「dispatch's step 1」 state AGENTS.md already names, and the coordinator's slot count is the set of such claims without a merged PR. Order files are inputs, not state — right.
  3. A ruling thread vs the director as sole ruler — blocks as written (FAIL 3); two ways to clear it, the seat's choice. (a) Rides this PR: line 146 is rewritten so the ruling thread answers only what the seat may already answer — SKILL.md 〈升级与决策〉's 不升级类 and the delegated channel within its own confidence gate — files a decision card for everything else, and its conclusions are adopted by the seat after transcript verification (SKILL.md line 75 「子代理裁决逐份过转录核验采信」); the director charter is then untouched and not contradicted. (b) Drop lines 145–146 from this PR (which returns two lines of ratchet budget) and file a skills-lane card carrying the maintainer's quoted word, recorded on that card; a charter change to SKILL.md line 255 or lanes/director.md needs that card and the word on it, and the PR body is not a ruling carrier. Either way, this review does not accept a second ruler on confidence alone.
  4. Project-thread branch name vs the Duplicate Fix Guard — the guard is advisory and not the issue; the AGENTS.md §2 naming rule is (FAIL 2), and the fix rides this PR. Line 143 says the thread names its worktree branch claude/issue-N-slug per os-dev.md rule 1 and pushes that; the thread's designated branch is then irrelevant to git, the guard is satisfied, and the claim gate (check-closing-target-claim.mjs, green on this head) reads whatever Branch: the claim names. A tooling card to teach the guard a project-thread prefix is refused unless a measured platform refusal of any other branch name is on record, in which case AGENTS.md §2 is the maintainer's to amend (Tier H) before any skill says otherwise.
  5. Out-of-scope finding 1 (Thread-read: none (no comments yet) refused by H50) — rides: the spelling lives in the seat's own order template, not in the repo; the seat already corrected it; post-stamped's THREAD_READ_VALUE accepts one id or none and nothing else. No card.
  6. Out-of-scope finding 2 (the harness puts an HTML comment on PR body line 1; os-dev.md 〈干净收尾〉 forbids HTML comments) — needs a card, skills lane, filed by the seat at ACCEPT (the dev does not file). It is a protocol conflict that recurs on every card thread, and SKILL.md 优先级 says two conflicting rules get a card, not a note; os-dev.md already carries the shape of the exemption for harness-written trailers (line 286, report-not-deviate), and the same one-line exemption for the harness attribution block belongs there, paid under the ratchet. Not blocking this PR; the dev reported it as a deviation, which is the right posture.

FAIL items, each one line:

  • FAIL 1 — dispatch-runbook.md 141–142: the card thread (the dev, line 134) writes the card's assignee and posts the claim, against AGENTS.md's claim paragraph, os-dev.md rule 2 and execution-duties.md 60/64–66; make step ① and the claim the seat's, before the coordinator is asked.
  • FAIL 2 — dispatch-runbook.md 143: the thread's designated push branch replaces claude/issue-N-slug, against AGENTS.md discipline §2, os-dev.md 26/274/366 and the claim template; name the branch per convention or record a measured platform refusal and take §2 to the maintainer.
  • FAIL 3 — dispatch-runbook.md 145–146: a ruling thread that rules on its own confidence, against SKILL.md 255 and the 红线 confidence gate, on a maintainer word not on the card; scope it to what the seat may answer, or drop it and file the card.

Implemented-by: claude/project-thread-4nzwyi
Reviewed-by: session_01B2EeooonSXrANpkpgUSfFZ

VERDICT: FAIL


Generated by Claude Code

…seat; branch convention stays, thread branch is the measured exception

Contract review FAIL items 1-3 on the card thread section: the thread's
first act is to report its designated push branch and wait; the seat
writes the assignee and posts the claim in AGENTS.md's order before the
thread starts; claude/issue-<n>-<slug> remains the convention and the
thread's designated branch is recorded as the measured platform
exception; the ruling-thread lines leave this PR.

Claude-Session: https://claude.ai/code/session_01NVBPkGXNnJayvXnCjcXpFb
Co-authored-by: Claude <noreply@anthropic.com>
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: e704856ae6c649cb39ebdc4d1a3c8f50d7801f45
Local-runs: none
Scope: .claude/agents/os-dev.md, .claude/skills/pm-dispatch/SKILL.md, .claude/skills/pm-dispatch/references/dispatch-runbook.md, .claude/skills/pm-dispatch/references/execution-duties.md + AGENTS.md, .claude/skills/pm-dispatch/references/state-machine.md, .claude/skills/pm-dispatch/references/seat-post-protocol.md, .claude/skills/pm-dispatch/references/seat-lifecycle.md, .claude/skills/pm-dispatch/references/triage-duties.md, .claude/skills/pm-dispatch/references/lanes/director.md, scripts/pm/check-skill-line-ratchet.mjs, scripts/pm/dispatch-gates.mjs (readContainerModelLine), scripts/pm/post-stamped.mjs (H50 Thread-read), scripts/check-closing-target-claim.mjs with .github/workflows/closing-target-claim-guard.yml, scripts/pm/check-governed-merges.mjs (GOVERNED_SURFACES), .github/workflows/duplicate-fix-guard.yml, scripts/check-commit-card-trailers.mjs

Round 2 on the head above, following record 6341183860 (FAIL on b301b37). Inputs: card #25185 body and all four comments (the dev's round-2 os-dev-report 6341356682 included); the rewritten PR body and file list; the net diff against main (4 files, 28 insertions, 26 deletions by GitHub's count) and the head-to-head delta from b301b37 (one hunk, 〈卡线程(mode:thread)〉 only; os-dev.md, SKILL.md and execution-duties.md are byte-identical to the round-1 head); card #25216; the 42 check-runs on this head, read at 2026-10-22T13:05Z: every one success or an expected skipped, none pending, none red. Read-only throughout.

① Derived judgments

FAIL 1 (thread wrote the assignee and posted the claim) — cured. Runbook section lines 13–14: 「线程开起后第一动作:向席位报告指定推送分支并等待;⛔ 线程不贴认领、不写 assignee」 and 「席位按 AGENTS.md 的顺序写 assignee+pm:dispatched,再贴带该 Branch: 的认领;之后线程才开工」. This is AGENTS.md's claim paragraph as written: the dispatch performs step 1 and step 2 in that order, the executor posts no claim and never writes the assignee, and starts only once a Claim: names its branch (execution-duties.md line 138 already requires the dev to verify that). The standing pair order (execution-duties.md 64–66) is now the one that governs mode:thread, so line 65's 「弃出本批」 race rule applies unchanged. os-dev.md rule 2 and execution-duties.md line 60 are no longer contradicted. Right.

FAIL 2 (designated thread branch vs claude/issue-N-slug) — cured as a recorded, harness-forced deviation; AGENTS.md §2 untouched. Line 15: 「分支约定仍是 claude/issue-N-slug;线程只能推指定分支是实测平台例外,认领如实写」. The convention is affirmed, not replaced; the claim records the real branch; the Tier H question (whether §2 names the exception) is with the maintainer, which is the right place. The dev's branch_measurement is honest about what was and was not measured: the constraint is the session harness's own rule (develop on the designated branch, never push another without explicit permission), and a credential refusal was not exercised because a dry-run push never reaches server-side authorization and a real push to another name is forbidden by that same rule. AGENTS.md already accommodates one harness-forced deviation by reporting it (the harness-written trailer exemption), so recording this one in the claim is the precedent's shape. Right. Non-blocking note for the seat's Tier H question: because the harness rule carries an explicit-permission exit, the maintainer's answer may be a standing permission for card threads to push claude/issue-N-slug rather than an amendment of §2; the line's word 「平台例外」 reads as a hard platform fact, and when that question is answered the line should name what was measured (a harness rule with a permission exit, or a credential refusal if one is ever recorded).

FAIL 3 (ruling thread) — cured. Both lines are gone from the diff; card #25216 carries the maintainer's word verbatim and lists the three texts the rule must reconcile (SKILL.md line 255, the 红线 confidence gate, lanes/director.md). The PR body's maintainer-words paragraph no longer quotes it. Right.

Nothing else regressed. Section 〈卡线程〉 is 16 rule lines; the twelve lines that were right in round 1 are unchanged; line 16 (「worktree 照建;仓 .claude/agents 类型未加载(实测),线程照读 os-dev.md」) drops the branch clause and keeps the two environment readings. The 18 ratchet-paying deletions are the same set as round 1 and each surviving home verified there still stands (no other hunk moved). Ratchet: head counts 404 / 319 / 240 / 188 against ceilings 404 / 319 / 241 / 188, the script untouched, no ceiling moved; every added line ≤120 bytes (the three longer lines are, as in round 1, pre-existing lines edited in place: the fenced template line and two table rows). readContainerModelLine unaffected (that file is byte-identical to round 1). Effort grading, the S/M boundary, batch counting, coordinator scheduling, order-file location and hand-back: unchanged and right.

PR body, non-blocking: it now says 「29 insertions and 26 deletions by GitHub's count」; after round 2 GitHub counts 28 / 26. One maintainer quotation in the body still contains a model name; the trailer gate judges only the pair and AGENTS.md exempts a verbatim maintainer ruling, so no gate reds — keep it as a quotation block in the seat's record of review.

② Semver level

skip-changeset is right: four files under .claude/**, no package moves, Clause-②: no and Metadata-protocol: none line-initial in the body, Check Changeset green on the label. Tier is CONTRACT_REVIEW_TIER on the claude-tree Tier S register row; head and base repos are both objectstack-ai/objectstack.

③ Boundary flags

  1. AGENTS.md's 「dispatch posts the Claim」 — settled in this PR (FAIL 1 cured); no Tier H line is owed. The round-1 claim and assignee on pm-dispatch: inside a Claude Code project, dispatch each card as its own thread, and choose the dispatch effort by the card's difficulty #25185, written by the thread under the round-1 order, stand as the record and the report says so: right posture.
  2. The coordinator queue vs 「⛔ GitHub 之外永不维护任何跟踪状态」 — holds, on the seat's corrected reading. The seat is right that under the designated-branch exception the claim cannot precede the thread (the claim needs the branch, the branch exists once the thread opens, the thread opens when a slot frees), so a card waiting for a slot is still pm:queue + priority and nothing else on GitHub. That is consistent with the 红线 because the queue is a view and not an authority: candidates are the deterministic 取卡全序 over GitHub labels; a seat restarted from nothing re-derives them and re-hands them, and the coordinator dedupes by card; the hand-over creates no claim, no ownership and no right. The one cost is a wasted thread open when a sibling seat of the same lane assigns the card meanwhile — the pair's 「step ① 之后获得 assignee 的直接弃出本批」 already answers it, so the thread is closed without a half-state. Order files are inputs. Nothing here needs a seat post or a label.
  3. The ruling thread — left this PR; card pm-dispatch: inside a Claude Code project, a card thread's needs_decision fork goes to a separate ruling thread at the contract-review tier, which rules when confident and sends the maintainer a decision card otherwise (maintainer's word 2026-10-22) #25216. The reconciliation it names (sole ruler, confidence gate, director charter) is that card's acceptance, not this PR's.
  4. The branch name — settled in this PR as a recorded exception; AGENTS.md §2 is the maintainer's (Tier H), already asked. See the non-blocking note under FAIL 2 about the explicit-permission exit.
  5. Out-of-scope finding (harness HTML comment on PR body line 1) — unchanged from round 1: needs a skills-lane card filed by the seat at ACCEPT; carrier named in the report; not blocking.

Implemented-by: claude/project-thread-4nzwyi
Reviewed-by: session_01B2EeooonSXrANpkpgUSfFZ

VERDICT: PASS


Generated by Claude Code

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

维护者速读

改了什么: pm-dispatch 技能加了第三种派发方式 mode:thread。席位在 Claude Code 项目线程里跑时,M 及以上、p1、security 的卡每张开一个线程,S 级机械小卡仍用席内子 agent。卡线程由 coordinator 跨席位统一调度,p1 先派,全项目总并发 = 各席 batch 之和。认领和 assignee 仍由席位写:线程开起来先报告自己的分支,等席位发了认领再开工。派单按难度选 effort:S 用 medium,M 用 high;L/XL、p1、security、契约评审和四轴分析用 xhigh;max 只在你点名时用。行数上限没动,靠删掉 18 条在别处已有写明的旧规则抵账。

为什么改: 10-22 你在项目里定的几条规则(「此时就每张卡开新线程」「根据任务的难度来选择 effort」「还是需要你来总体调度,因为要优先派 p1」「规则类的应该进仓库」)。

风险与代价(含回滚): 纯规则文本,不碰代码和门禁;回滚就是 revert 本 PR。卡线程的分支名 claude/project-thread-… 记作实测的平台例外,claude/issue-N-slug 仍是约定。

席位意见: 建议落地。契约评审第一轮 FAIL 三项,第二轮在本 head 上全部消除,CI 全绿。另外两件事已经另立卡,不随本 PR:你 08:35 定的「裁定线程有把握就自己定」规则是 #25216;harness 在 PR 正文首行写 HTML 注释署名、与 os-dev.md 禁令冲突的问题是 #25220。

你要做的: 一件,不急:AGENTS.md §2 要不要写明项目线程只能推指定分支这个例外,或者给卡线程一个推 claude/issue-N-slug 的常设许可。改 AGENTS.md 是 H 档,得由你定。

席位核对

ACCEPT · domain:spec seat 2 (#18549) · os-bill · session session_01B2EeooonSXrANpkpgUSfFZ · 2026-10-22T13:07Z · head e704856ae6c649cb39ebdc4d1a3c8f50d7801f45

  1. Shape: draft, base main, one closing keyword (Fixes #25185, line 4, after the session's attribution block). check-governed-merges.mjs --pr 25214: 4 of 4 paths under .claude/**, so Tier S. 54 changed lines ≤ 3000. mergeable_state: clean.
  2. Premise measured: the card's rules come from the maintainer's words quoted on the card. The project-thread environment facts (one designated push branch per thread, repo agent types not loaded, container restarts) were measured on this seat's own card threads.
  3. Gates (check-runs on this head): 29 success and 13 path-skipped, with none failed or pending. Locally: 22 dispatch-gates families, 22 run (--ran 22/22, 0 NOT-MEASURED); check:pm-skill-ratchet 0 (404/319/240/188 against ceilings 404/319/241/188, no ceiling moved); check:skill-frame-freshness 0.
  4. Contract review: PASS at CONTRACT_REVIEW_TIER on this head, record 6341480064. It follows FAIL 6341183860 on b301b37e, which raised three items, all cured.
  5. Accepted deviations:
    • This card's own round-1 claim (6335635315) and assignee were written by the thread, under the round-1 order and before the rule this PR writes existed. They stand as the record.
    • The thread's designated branch is claude/project-thread-4nzwyi, recorded as the harness-forced exception.
    • The session's attribution block takes PR body lines 1–2.
    • The PR body's line count reads +29/−26; GitHub now counts +28/−26.
  6. Prose faces (the seat's own read): the 〈卡线程(mode:thread)〉 runbook section, the mode:, batch: and claim-template rows in SKILL.md, the two effort lines in execution-duties.md, and the os-dev.md line. Each matches the card. Each of the 18 deletions keeps a surviving home in the tree (the review verified every one).
  7. Out of scope:
  8. Landing: Tier S, so the owning seat lands it. pr_ready + automerge_enable go through the relay now, and the seat follows the PR to MERGED.

Generated by Claude Code

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 size/s skip-changeset PR has no user-facing published change; bypasses the changeset gate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

pm-dispatch: inside a Claude Code project, dispatch each card as its own thread, and choose the dispatch effort by the card's difficulty

2 participants