Skip to content

Commit 9856a65

Browse files
committed
feat(agents): pm-dispatch escalation bar — obvious fixes ship, the maintainer gets a veto window, not a permission gate
Maintainer feedback after #3182 sat waiting for confirmation: obvious problems should just be fixed. Escalation now requires genuine product/ contract divergence with no repo-norm answer, or destructive/irreversible action. Named non-escalation classes act immediately: restore-invariant fixes (dual-version dependency graphs, inert tripwires, unwired gates), sequencing, verification strategy, and dev needs_decision reports that fall into those classes (the PM answers the dev directly). Also records the GitHub body-sanitizer generics trap in the os-dev definition. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012C2cd7tL8QDoZ2QKN3djJ5
1 parent 85a966f commit 9856a65

3 files changed

Lines changed: 41 additions & 2 deletions

File tree

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
---
3+
4+
Internal agent tooling only (`.claude/` pm-dispatch escalation bar + API-body generics trap) — releases nothing.

.claude/agents/os-dev.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,3 +89,10 @@ Final message — exactly this JSON, no prose around it:
8989

9090
Use `status: "rework"` for a partial result you know is incomplete (say why in
9191
`summary`); the PM will review and re-dispatch with feedback.
92+
93+
Practical trap when filing issues/PRs through the GitHub API: the body
94+
sanitizer strips `<` followed by a letter as an HTML tag **at rest**, which
95+
destroys TypeScript generics (`Assert<Equal<1, 2>>` is stored as `Assert>`).
96+
Write generics with a space after each `<``Assert< Equal< 1, 2 > >` is
97+
still valid TypeScript — and read the stored body back to verify when a
98+
snippet is load-bearing.

.claude/skills/pm-dispatch/SKILL.md

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -313,8 +313,36 @@ Verdict per issue:
313313

314314
### 8. Escalate uncertainties to the maintainer
315315

316-
Whenever a dev returns `needs_decision`, an issue is too vague to dispatch, or
317-
rework has failed twice:
316+
**First, apply the escalation bar — most things that FEEL like decisions are
317+
not.** The maintainer's words: 「明显的问题直接修,不是事事都需要我确认」.
318+
Escalate ONLY when at least one of these holds:
319+
320+
- the options genuinely diverge on **product semantics or public contract
321+
shape** and neither the issue, AGENTS.md, ADRs, nor existing code norms
322+
determines the answer;
323+
- the fix requires a **destructive or hard-to-reverse action** (stored-data
324+
migration shape, deleting a shipped capability, force operations).
325+
326+
Everything else is the PM's call — decide, dispatch, and give the maintainer
327+
a **veto window instead of a permission gate**: state what you decided and
328+
why in the issue comment and the round report; they can stop it, but you do
329+
not wait for them. Named non-escalation classes (act immediately):
330+
331+
- **Restore-invariant fixes.** When the repo already states the invariant —
332+
one contract version across the family, declared = enforced, a gate must
333+
actually compile/run what it claims to check — a finding that the
334+
invariant is broken carries its own decision. A dual-version dependency
335+
graph, an inert tripwire, an unwired gate: queue it, dispatch it, report
336+
it. Asking "may I restore the invariant?" is the anti-pattern.
337+
- **Sequencing and dependency ordering** between technical tasks.
338+
- **Verification strategy** (what regression pass a risky-but-decided change
339+
needs) — that is scoping the work, not deciding it.
340+
- A dev's `needs_decision` that, on PM review, falls into the classes above:
341+
answer the dev yourself with the decision and rationale; do not relay it
342+
upward.
343+
344+
Whenever a dev returns `needs_decision` that passes the bar above, an issue
345+
is too vague to dispatch, or rework has failed twice:
318346

319347
1. **Default: the decision lives ON the issue it belongs to — never a new
320348
issue.** Post the analysis as a comment on that issue, add the

0 commit comments

Comments
 (0)