Skip to content

docs(pm-dispatch): one batch cap for every subagent in flight, triage clean-up prepared one group at a time - #20108

Merged
objectstack-fleet[bot] merged 2 commits into
mainfrom
claude/issue-20084-subagent-concurrency-cap
Sep 25, 2026
Merged

objectstack-fleet[bot] merged 2 commits into
mainfrom
claude/issue-20084-subagent-concurrency-cap

Conversation

@objectstack-fleet

@objectstack-fleet objectstack-fleet Bot commented Sep 25, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #20084

Clause-②: no

Tier S (every path under .claude/**): this PR stays DRAFT — no ready flip, no enqueue, no auto-merge; it lands on the owning seat's contract-tier review of record.

What changed (three lines, three files, net 0 lines everywhere)

Maintainer ruling implemented as written (director seat chat, 2026-09-25, verbatim and untranslated): 「不要同时派发这么多」 · 「小心封号」 · 「同意,让 skills 车道立卡补上这条规则」.

  1. .claude/skills/pm-dispatch/SKILL.md — the batch row of the 入口与角色 table (L59), rewritten in place. The 含义 cell now defines batch as the seat's cap on EVERY subagent in flight, counted per Agent call and per create_session — dev, reviewer, census alike — with read-only explicitly not exempt. The 默认 cell (default 3, maintainer ceiling 5) is unchanged, and the priority:p0 row (L117, 「插队:可超 batch」) is untouched and not contradicted.
  2. .claude/skills/pm-dispatch/references/execution-duties.md L21, rewritten in place: the same cap in one line — 「batch 封顶全部子代理」 (the dev / 复核 / 普查 / 只读 enumeration lives in the SKILL.md batch row every seat reads first) — keeping 「等待不填槽;同批独立按文件面不相交判」 and the tail 「⛔ 不按包、不按 check 名」 verbatim (it has no other home on origin/main); 120 bytes, at the inclusive cap. Corrected by the seat after the patch round (head c66d03d): the first head cb2d8c4 had dropped that tail, and the seat's REWORK put it back.
  3. .claude/skills/pm-dispatch/references/filing-gate.md — one new line directly beside the groups-of-ten line (L27): the clean-up prepares only the NEXT group; while the current group is not maintainer-confirmed, the one after is not prepared and the batches are not fanned out in advance.

Ratchet accounting (headroom 0 on all three files; no ceiling touched)

file lines before → after note
SKILL.md 319 → 319 (ceiling 319) in-place row rewrite; batch row width 87 B → 191 B, widest-row pin 342 B untouched (widest row is another row, still 342 B)
references/execution-duties.md 183 → 183 (ceiling 183) in-place rewrite, 118 B → 120 B (cap 120, inclusive)
references/filing-gate.md 58 → 58 (ceiling 58) +1 rule line (119 B) paid by DELETING L28 「写节奏 ⛔ 非可选:REST 写(评论/标签/关单/立卡)间隔 ≥3 秒,每账号每小时 ≤40 笔。」

Payment rationale for filing-gate.md: the deleted line is a verbatim duplicate of SKILL.md L94 「写侧恒为 objectstack-fleet[bot](AGENTS.md);节奏 ≥3 秒/笔、每账号每小时 ≤40 笔,429 即停写。」, which every seat reads in full before any reference file; the references convention is one rule per line and no rule already stated in SKILL.md, so it was the lowest-value line in the section. Real deletion, not a re-wrap: no two lines were folded. The write pace stays enforced mechanically by write-pace.mjs and stated at its single source. L29 (429 ⇒ 停写并记座位贴) keeps its unique half and stays.

Gates at cb2d8c4 (derived with node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack, no paths; each exit captured before any pipe)

All 21 families exit 0: check-closing-keyword-parity (+ --self-test) · check-comment-mask-corpus · check-governed-queue-guard --self-test · check-harness-current --self-test · check:agent-test-spelling · check:cross-package-test-inputs · check:doc-authoring · check:driver-memory-census · check:gitlink-declared · check:nul-bytes · check:pm-expected-skips · check:pm-governed-merges · check:pm-governed-prose · check:pm-skill-id-lint · check:pm-skill-ratchet · check:refd-timer-probe · check:skill-frame-sync · check:watch-hint-literal · check:skill-frame-freshness (outside the derivation, cheap) · @objectstack/lint check:doc-formula-expressions (self-test + gate, after the closure build).

Ratchet verdict lines quoted from the gate: SKILL.md is 319 lines (ceiling 319; headroom 0) · widest table row is 342 bytes (pin 342; headroom 0) · execution-duties.md is 183 lines (ceiling 183; headroom 0) · filing-gate.md is 58 lines (ceiling 58; headroom 0).

Patch head c66d03d (one line, execution-duties.md L21): the same set re-run, every family exit 0 except check:doc-formula-expressions NOT MEASURED there (the gate does not scan .claude/**; exit 0 at cb2d8c4; CI runs it). The seat's ACCEPT (card comment 5827273568) and ## Contract review PASS record (PR comment 5827276360) are recorded for c66d03d.

维护者速读(草稿)

改了什么

把「同时在飞的上限」从「只数 dev」改成「数席位起的每一个子代理」:dev、复核、普查、只读全算,默认 3、天花板 5 不变;另加一条:分诊存量清理十张一组时只准备下一组,当前组你没确认之前不准备再下一组、不提前把所有批次都铺开。三处各改一行,文件行数一行没涨。

为什么改

今天总监席一次起了 8 个只读复核子代理加 1 个 dev,9 个同时用一个身份读 GitHub,被你叫停(「不要同时派发这么多」「小心封号」)。原规则写的是「dev 上限」,席位读成「复核不算」;封号警告都围绕写,席位读成「只读安全」。上一次封号之前的负载正是同一身份下的大量读。这三行把口子堵上,并按你的话「让 skills 车道立卡补上这条规则」落地。

风险与代价(含回滚)

纯文本、Tier S,不改任何脚本或门禁,不发布任何包(skip-changeset)。代价是 filing-gate.md 删了一行写节奏(≥3 秒/笔、每小时 ≤40 笔)——它与 SKILL.md L94 逐字重复,规则仍在 SKILL.md 且由 write-pace.mjs 机械执行,所以删的是重复不是规则。回滚 = revert 这一个 commit,三文件回到原样。

席位意见

(留空)

你要做的

读三行改动是否符合你的意思;若同意,由 skills 席按 Tier S 复核记录落地,不需要你点合并。

Follow-up note (card item ④ — a mechanical guard; NOT built here, and not recommended)

A live count of a seat's in-flight subagents is visible only to the harness (the Agent tool and create_session), not to any repo script: a pm:dispatched census would count devs and miss every reviewer/census subagent, which is exactly the class this card closes. No cheap guard exists; the decision frame's default for a new gate is 「不加」, and nothing here recommends one.

Acceptance notes / deviations


Generated by Claude Code

… clean-up prepared one group at a time

Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0148fenvVvyQV9HYxgVDQ33q
… the batch cap line

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

Copy link
Copy Markdown
Contributor Author

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: c66d03db5456bae448e3f236f3c5ec656721d638

① Derived judgments

  • Accept set / public surface: none moves — every changed path is under .claude/** (the seat protocol text); no package files[] ships it; no schema, error code, REST route or CLI flag is touched. The card's Clause-②: no holds.
  • SKILL.md :59, the batch row: the cap now counts every subagent a seat has in flight, per Agent call and per create_session, read-only not exempt — the ruling's ① as written; the priority:p0 row (may exceed batch) is untouched and not contradicted; row 191 B under the 342 B widest-row pin; file 319 / 319.
  • references/execution-duties.md :21: the same cap in one line, keeping 等待不填槽, 按文件面不相交判 and the tail ⛔ 不按包、不按 check 名 (no other home on origin/main aa04ea2 — measured by git grep); 120 B at the inclusive cap; file 183 / 183.
  • references/filing-gate.md: one new rule beside the groups-of-ten line (prepare only the next group; none prepared ahead while the current group is unconfirmed) — the ruling's ②; paid by deleting the write-pace line whose rule lives at SKILL.md :94 and is enforced by write-pace.mjs; no reader is pinned to the deleted line (git grep); file 58 / 58.
  • No issue number enters operational text (check:pm-skill-id-lint 0); the four-axis block is untouched (check:skill-frame-sync 0); governed prose intact (check:pm-governed-prose 0).

② Semver level

  • None owed: nothing published; skip-changeset is the correct declaration.

③ Boundary flags

  • Dev flags: none (open_questions empty in both reports). Seat flag: check:doc-formula-expressions NOT MEASURED at the patch head (the gate does not scan .claude/**; exit 0 at cb2d8c4; CI runs it) — accepted, not a blocker. Card item ④ (a mechanical guard): not built, noted in the PR body as not recommended — consistent with the frame's 「新增门禁默认否」.

Implemented-by: claude/issue-20084-subagent-concurrency-cap
Reviewed-by: session_0148fenvVvyQV9HYxgVDQ33q

VERDICT: PASS

Rendered in-seat at 2026-09-25T05:24Z on the fetched head (the branch fetched into a seat-owned ref), diff read three-dot against origin/main aa04ea2; landing = every check green on this head, then the relay.


Generated by Claude Code

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review September 25, 2026 05:42
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Sep 25, 2026
Merged via the queue into main with commit 7b27bd0 Sep 25, 2026
41 of 42 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/issue-20084-subagent-concurrency-cap branch September 25, 2026 05:56
akarma-synetal pushed a commit to akarma-synetal/framework that referenced this pull request Sep 28, 2026
…ility; same-family findings fold into one class-closure card; triage gates unproven ones to p3 (objectstack-ai#20110)

Fixes objectstack-ai#20088

Clause-②: no

Every path in this diff is under `.claude/**` (Tier S): the PR stays a
draft, is not readied, queued or armed by any seat, and lands only on a
contract-tier review of record. It publishes nothing from any package
`files[]`, so it carries `skip-changeset`.

## What changed — one rule, four sites, written as shapes

The maintainer's ruling on the card (triage seat chat, 2026-09-25,
verbatim): the triage seat answered 「立卡时由发现者确认,分诊只把关、不测量」 and the
maintainer said 「同意」. The three numbered clauses of the card's 裁决内容 are
implemented as written, at the four sites the card names. No card
numbers appear in the operational text (`check:pm-skill-id-lint` refuses
them there); the two precedents the card asks for are written as shapes.

- **`.claude/agents/os-dev.md` rule 3 — the finder.** Every (a)(b)(c)
finding carries a `reach:` entry: one measured wrong answer at a public
door (HTTP / UI / `os validate` / save), or one named real producer.
Read-only inference is listed among what is not a card and goes to `##
Acceptance notes` with `carrier:`. The three exceptions still report —
possible data exposure, wrong text that a release would freeze,
maintainer-directed — with `reach:` naming which. A same-family finding
is pointed at the family's class-closure card in the report instead of a
second single-site card; the definition lives in the pm-dispatch 报告契约.
The report JSON's `out_of_scope_findings` example line gains the
`reach:` field (one edited line inside the fence; nothing else in the
block moved).
- **`.claude/skills/pm-dispatch/SKILL.md` 报告契约 — the seat.** `reach:` is
required on every entry; no measurement ⇒ no card, with the exceptions
and the definition at 立卡门 ①; the reports of one round are cross-read and
a family opens one card. The class-closure card is defined once here:
one card covering every site of the family, one pin that enumerates the
sites; when none exists, the second occurrence opens it. The four-axis
block (:241–:261) is byte-unchanged (md5
`abff5f852c8fd09b79ec0623439aa4f0` before and after).
- **`references/triage-duties.md` — the gate.** All three classes owe
`reach:`; triage gates and does not measure. Missing evidence and not an
exception ⇒ `priority:p3`, folded into the closure or sweep card, never
dispatched alone, and triage never takes the card off the board for that
reason (关卡归维护者). The old 「同族异缺陷 ⛔ 不并:互链排同批」 sentence is replaced for
findings; in-flight cards (assignee / open PR) are still never merged,
`Blocked-by:` is still not dispatched, completion still re-checks
staleness.
- **`references/filing-gate.md` ① — the definition.** A `finding` inside
① is limited to the three classes AND carries `reach:`; the two accepted
forms; the three exceptions, whose first execution item is 「先测可达性」; and
the two precedents as shapes — a card whose body itself says 未测量 is not
filed (Acceptance notes with a carrier); a card recording one measured
wrong answer at a public door is filed.

Not done, by the card's own terms: no new `check-*` gate; no retroactive
re-triage of existing cards; the 过渡期 sentence stays as the card states
it (triage already runs clause ③; clauses ① and ② take effect for the
other seats when this lands); `.claude/settings.json` untouched.

## Ratchet payment — every file stays at its ceiling, paid inside its
own section

| file | lines before | lines after | ceiling |
|:--|--:|--:|--:|
| `.claude/agents/os-dev.md` | 402 | 402 | 402 |
| `.claude/skills/pm-dispatch/SKILL.md` | 319 | 319 | 319 |
| `.claude/skills/pm-dispatch/references/triage-duties.md` | 120 | 120 |
120 |
| `.claude/skills/pm-dispatch/references/filing-gate.md` | 58 | 58 | 58
|

Every prose line is at most 120 bytes; no re-wrap was used as payment.
What paid, and why it is equal-or-lower value:

- os-dev.md — 「(a) 须今天可达,分错误与不完整…示例照抄即失败是 (a),漏列成员不是」 is subsumed by
`reach:` (copying the example is a measured wrong answer at the
authoring door; a missing member measures nothing) and survives verbatim
for the triage seat at triage-duties :44; 风格/nit left the not-a-card
list (抛光 covers them) to make room for 只读推断; the pointer line to
`rest-channel.md` is deleted (the dev's four writes go through
`scripts/pm/` tools that choose the route; the table is the seat's); the
two dedupe lines are merged, dropping 「预算外零写」 (it restates the
four-write budget beside it) and 「只复核其后增量」 (it contradicted 「dev ⛔
不查重」).
- SKILL.md — the JSON-shape pointer and the `needs_decision` line are
merged; the twin-card cross-read line is replaced by the fold rule,
which carries 「同轮报告互读」.
- triage-duties.md — the instrument line is deleted: it duplicates
`instrument-discipline.md` :6 and :8 verbatim, reached through :41's
pointer to the filing gate's ⛔ list.
- filing-gate.md — 「原为首触即关,今门前即拒」 (history, not a rule) is dropped from
the 三类外 line, which now also names the unmeasured `finding`; the 丢卡重建
and sweep-reminder lines are merged; the fleet-identity line is deleted
as a verbatim duplicate of SKILL.md :94 (全体座位的不变量). **Re-merge (head
`247e355d`, after PR objectstack-ai#20108 landed):** the write-pacing line this branch
first paid with had been REPLACED on `main` by objectstack-ai#20108's 「十张一组只备下一组…」
rule, which is kept verbatim; the payment moved to the ⛔-list row 「⛔
不是卡:仪器误报与门禁假读数(不派 dev 见 `references/instrument-discipline.md`)。」, whose
rule lives verbatim at `references/instrument-discipline.md` :6 / :8 and
stays reachable from `references/reading-discipline.md` :26. Three-dot
diff unchanged: 4 files, +21 / −21; 58 / 58.

## Deviations from the dispatch, measured

- 「先测可达性」 as the first execution item is written at the filing gate ①
(the seat's definition) and pointed at from SKILL.md, not in os-dev.md:
the dev never writes a card body (os-dev.md rule 3, 「dev 不 `POST
/issues`」), so the sentence has no reader there. os-dev.md carries the
exceptions as the finder's reporting duty (`reach:` names which).
- The dispatch named os-dev.md :41–:60 as this card's region; rule 3
runs to :67. Every edit sits inside :45–:60.
- The four sites sat exactly where the dispatch cited them on
`origin/main` `8d76c2d` (identical to `d624002` for these paths).
Same-day churn: nothing landed on the four paths after the branch point;
`origin/main` moved once (`aa04ea29`, objectql) with no overlap.

## Verification

Gate families derived from the real change set (`node
scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack`, no
paths, three-dot against merge base `8d76c2d`), all run at head
`b985bd39`, each exit captured before any pipe; `--ran` reconciliation:
23 derived, 23 run, 0 NOT-MEASURED (a derived zero — every family
recorded its exit code).

- exit 0: `check-closing-keyword-parity.mjs` (gate and `--self-test`),
`check-comment-mask-corpus.mjs` (7156 files, 0 disagree),
`check-governed-queue-guard.mjs --self-test` (279 cases),
`check-harness-current.mjs --self-test` (26 cases),
`check:agent-model-declared`, `check:agent-test-spelling`,
`check:commit-card-trailers` (also run by the pre-push hook: 1 commit,
no card relation, no model identifier),
`check:cross-package-test-inputs`, `check:doc-authoring`,
`check:driver-memory-census`, `check:gitlink-declared`,
`check:nul-bytes`, `check:pm-expected-skips`,
`check:pm-governed-merges`, `check:pm-governed-prose` (2 surfaces name
all 6 governed surfaces), `check:pm-half-states` (4912 cases),
`check:pm-skill-id-lint` (34 files clean), `check:pm-skill-ratchet` (157
self-test cases; the four files at 402/319/120/58 against ceilings
402/319/120/58), `check:refd-timer-probe`, `check:skill-frame-sync` (one
declared copy, coherent), `check:watch-hint-literal`.
- exit 0: `pnpm --filter @objectstack/lint run
check:doc-formula-expressions` — its prerequisite, the closure
`@objectstack/lint...` (spec, formula, sdui-parser, lint), was built
under the shared verify lock (`os-verify-lock.sh` VERDICT command-exit
0, held 203s, 4/4 turbo tasks); 22 record-scoped examples across 456
files judged clean.
- exit 0, outside the derivation: `check:skill-frame-freshness` (the
frame is current with `origin/main`).
- Not owed and not run: no package source changed, so no `pnpm test` /
`pnpm typecheck` closure; `pnpm lint` is CI's run.

## Acceptance notes

No out-of-scope findings. The (a) boundary lesson (示例照抄即失败是 (a),漏列成员不是)
now lives only at triage-duties :44; under `reach:` the same question is
answered by measurement.

## 维护者速读(草稿)

**改了什么** — 四处协议文本改成同一条规则:发现者立卡前先测可达性 —— 公开入口(HTTP、界面、`os validate`
或保存)实测出一次错误结果,或点名一个已存在的真实生产者 —— 写进 `reach:` 一栏;只读代码推断不立卡,进 PR 的
Acceptance notes
并带承接者。三种例外(可能泄露数据、随发版固化的错误文字、维护者直派)未测量也照立,执行要点第一条写「先测可达性」。同族发现并入该族收口卡(一张卡覆盖全部位置、带一个能枚举全部位置的钉子),不再逐点开卡。分诊只把关不测量:缺可达性证据又非例外的定
p3、并入收口卡或清扫卡,不单独派发,也不因此关卡。

**为什么改** —
维护者在分诊席会话的裁决(2026-09-25,逐字):维护者问「理论上的问题建议时分诊时确认还是立卡时确认?」,分诊席答「立卡时由发现者确认,分诊只把关、不测量」,维护者:「同意」。分诊席的读数:一夜
55 张新卡全部来自 dev 报告的顺路发现,大量卡面自注「未测量」,同一缺陷族连环立卡,开放卡数持平 —— 修复速度赶不上顺路发现的速度。

**风险与代价(含回滚)** — 风险:未测量的 (b) 类发现不再成卡,只留在 PR 的 Acceptance
notes,若承接者为无则可能被遗忘;三种例外兜住安全、发版固化与直派。代价:四个文件都在行数上限,每条新句都以删掉一条被新规则涵盖或在别处逐字重复的旧句付账(清单在上文
Ratchet payment 节);没有新增门禁、脚本或数据变化。回滚:revert 本 PR 的单个 commit 即可,四个文件回到原样。

**席位意见** — (留空,由席位定稿成评论)

**你要做的** — 本 PR 只改 `.claude/**`(Tier S),保持 draft;席内契约复核记录 PASS
后由席位入队落地,不需要维护者的合并点击。维护者只需确认:第 1、2 条从本 PR 落地起对其他席位生效;第 3
条分诊席已按过渡期条款先行执行。

---
_Generated by [Claude
Code](https://claude.ai/code/session_0148fenvVvyQV9HYxgVDQ33q)_

Co-authored-by: Claude <noreply@anthropic.com>
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/xs skip-changeset PR has no user-facing published change; bypasses the changeset gate

Projects

None yet

1 participant