feat(escalation): escalate dev→boss after N silent failures (B11) #440
No reviewers
Labels
No labels
area:agents
area:dashboard
area:database
area:design
area:design-review
area:flows
area:infra
area:meta
area:security
area:sessions
area:webhook
area:workdir
security
type:bug
type:chore
type:meta
type:user-story
No milestone
No project
No assignees
3 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
charles/claude-hooks!440
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "dev/427"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
silent_failure_countfield toTaskRequest(consumed by B11; B10 will populate it on re-dispatch)escalation.tsmodule withcheckAndRecordEscalation(): decidesescalate | dead_letter | passbased on per-typeescalation_target+max_escalations_per_day(default 10); daily cap auto-resets at local midnight via aYYYY-M-Dcache keyagent.dispatchnode: whensilent_failure_count >= 1, callscheckEscalation; onescalate→ re-routes to target type, patches request identity (token/user/name/email/branch_prefix), and fires an audit comment; ondead_letter→ broadcastsflow:dead-letterSSE and emitsFILTER_DROPconfig/agents.json:devandreviewertypes gainescalation_target: "boss"andmax_escalations_per_day: 10escalation.test.tscovering all four decision pathsCloses #427
Test plan
bun test apps/server/src/domain/dispatch/escalation.test.ts— 11 tests passbun test apps/server/src/domain/flows/agent-nodes.test.ts— 38 existing tests passbun x tsc --noEmitinapps/server— no errorsbun x biome checkon changed files — cleanba7a8f833db4e43c455cCI green. All acceptance criteria met. Logic is correct.
escalation.ts: counter design is clean —todayKey()comparison drives midnight rollover without a scheduled job; dead-letters don't consume budget; counter only increments on actual escalation. ✓agent.dispatchnode: escalation block fires only whensilent_failure_count >= 1and acheckEscalationinjection is present;request.branch(explicit override) is preserved; identity fields patched to target-type credentials; audit comment is fire-and-forget with logged catch. ✓webhook-config.ts:escalation_targetis optional (absent = no escalation),max_escalations_per_daydefaults to 10 and is validated as a non-negative integer. ✓config/agents.json:devandreviewergainescalation_target: "boss"andmax_escalations_per_day: 10. ✓Nit (non-blocking):
todayKey()usesd.getMonth()which is 0-indexed, producing keys like2026-3-5for April 5 instead of2026-4-5. Rollover logic is functionally correct (the key still changes at midnight), but the stored value diverges from theYYYY-M-Ddocstring. Worth a one-liner fix when convenient.Squash-merge refused by Forgejo:
HTTP 405. Required workflow run #2286 iswaiting(no runner has picked it up — duration 0s). Will retry once the run reportssuccess.