What was measured (2026-08-16, cloud-lane PM session, remote container)
- Before this session made its first GitHub call, the fleet's shared identity had the GraphQL pool at 10004/5000 used (2x overdrawn) — every seat sharing the identity pays for every other seat's burn.
- Every MCP list tool then failed for the rest of the hour:
list_issues / search_issues are GraphQL-backed server-side; there is no REST list path via MCP. - Claims were unsafe the whole time:
issue_write (assign/labels) is GraphQL-bound while comments are REST — so the atomic claim pair (assign + claim comment) could only be half-executed, which the protocol forbids. The seat sat idle until the hourly reset. - Cost amplifier measured in the same incident:
search_issues died inside failed to fetch issue field values — the MCP layer fans out extra per-issue GraphQL calls to fetch Project field values that no pm-dispatch code path reads (org Project is explicitly not in the hot path).
Gap
The skill's quota doctrine is post-hoc only ("配额打满:待执行写操作排成有序清单挂进巡逻词…"). Nothing gates entering a round against the remaining budget, so a round can start, read half a lane, and strand at the claim step.
Proposed skill change (for the skills seat to triage)
- Pre-round budget gate: the probe-first step additionally reads
rate_limit (free; counts against no pool). If GraphQL remaining is below ~1000 points, the round runs REST-side actions only (comments, issue_read); list reads and claims are deferred as a whole to the reset window. Never begin a claim that cannot complete its pair. - Field hygiene: every
list_issues / search_issues call passes an explicit fields subset that omits field_values, eliminating the measured per-issue GraphQL fan-out.
Constraints
Fix lands in .claude/skills/pm-dispatch/** → domain:skills; dispatch model claude-fable-5 mandatory; human review + human merge (skills are ADR-class); ratchet/lint guards per their script headers (pnpm check:pm-skill-ratchet, pnpm check:pm-skill-id-lint).
Provenance
Filed at the maintainer's direction in the 2026-08-16 PM session (「给 skills 席位写 issue」), after the incident above was diagnosed live in that session. Sibling card filed in the same batch: platform-readings facts-table update.
Generated by Claude Code
What was measured (2026-08-16, cloud-lane PM session, remote container)
list_issues/search_issuesare GraphQL-backed server-side; there is no REST list path via MCP.issue_write(assign/labels) is GraphQL-bound while comments are REST — so the atomic claim pair (assign + claim comment) could only be half-executed, which the protocol forbids. The seat sat idle until the hourly reset.search_issuesdied insidefailed to fetch issue field values— the MCP layer fans out extra per-issue GraphQL calls to fetch Project field values that no pm-dispatch code path reads (org Project is explicitly not in the hot path).Gap
The skill's quota doctrine is post-hoc only ("配额打满:待执行写操作排成有序清单挂进巡逻词…"). Nothing gates entering a round against the remaining budget, so a round can start, read half a lane, and strand at the claim step.
Proposed skill change (for the skills seat to triage)
rate_limit(free; counts against no pool). If GraphQL remaining is below ~1000 points, the round runs REST-side actions only (comments,issue_read); list reads and claims are deferred as a whole to the reset window. Never begin a claim that cannot complete its pair.list_issues/search_issuescall passes an explicitfieldssubset that omitsfield_values, eliminating the measured per-issue GraphQL fan-out.Constraints
Fix lands in
.claude/skills/pm-dispatch/**→domain:skills; dispatch modelclaude-fable-5mandatory; human review + human merge (skills are ADR-class); ratchet/lint guards per their script headers (pnpm check:pm-skill-ratchet,pnpm check:pm-skill-id-lint).Provenance
Filed at the maintainer's direction in the 2026-08-16 PM session (「给 skills 席位写 issue」), after the incident above was diagnosed live in that session. Sibling card filed in the same batch: platform-readings facts-table update.
Generated by Claude Code