Files
roboco/docs/rag/workflows/escalation.md
T
60c64c70e8 fix(run-hardening): break PM decision-gate, stale-agent, and empty-diff loops (#255)
Forensic triage of a 24h run reconstructed the dominant gateway.rejected
loops from the audit_log. After earlier deploys fixed the i_will_plan crash
and the open_pr push-gap, three real, recurring-capable burn loops remained.
This fixes them at the architecture level, not by prompt-nagging.

journal:decision write-then-gate (the dominant completion-path blocker):
PM decision-point verbs required a separate note(scope='decision') call
before the verb, which loaded/weak models forget to chain — so complete and
unblock hit a tracing_gap (journal:decision missing) and respawn-looped,
stranding finished tasks forever. Each verb now auto-records its OWN
rationale as the journal:decision before the gate runs (the proven
i_am_blocked -> write_struggle pattern), so the gate passes off real,
persisted reasoning. unblock gains a required `reason` (threaded MCP tool ->
request schema -> routes -> choreographer); delegate derives the decision
from its title + description; complete/submit_up/submit_root/escalate_up/
escalate_to_ceo reuse their existing notes/reason. The gate still runs as
defense-in-depth; the auto-record is idempotent within the decision window
and best-effort. Adds JournalService.write_decision and
Choreographer._ensure_pm_decision.

open_pr empty-diff 422: an overlapping-decomposition leaf with zero commits
vs its base makes GitHub 422 "No commits between ...". The generic
invalid_state "retry" looped the dev 15x on one task. open_pr now steers to a
terminal i_am_blocked hand-off so the PM completes or cancels the redundant
leaf.

owns_task stale-agent loop (41x): a superseded agent (task reassigned away)
calling i_am_done/open_pr got a PRECONDITION_OWNERSHIP tracing_gap it read as
a fixable precondition and retried forever. Both verbs now short-circuit with
the clear not_authorized "no longer yours -> give_me_work" steer that
resume/unclaim already use.

RAG docs updated for the new unblock(reason) signature; CHANGELOG entries
added under 0.11.0 (unreleased). open_pr refactored into
_open_pr_preflight_rejection + _open_pr_failure_env to stay within the
return-count and complexity budgets.

Co-authored-by: Renn F <rennf93@users.noreply.github.com>
2026-06-25 01:07:05 +02:00

3.0 KiB

Escalation Workflow

Escalation Chain

Developer/QA/Documenter
         ↓
      Cell PM
         ↓
      Main PM
         ↓
   Product Owner / Head of Marketing (Board)
         ↓
        CEO

escalate_up walks this chain one rung at a time — it auto-routes to your immediate escalation target; you cannot choose a higher level or skip a rung.

The one exception is escalate_to_ceo: it is a separate verb, available only to Main PM and the Board (Product Owner / Head of Marketing), that goes straight to the CEO for final approval of a major task. It is not part of the escalate_up chain.

How to Escalate (up one rung)

escalate_up(
    task_id="<task>",
    reason="Need clarification on the API contract",
)

Auto-routes to your escalation target (you cannot choose it).

When to Escalate

Situation Escalate To
Unclear requirements Cell PM
Blocked by external factor Cell PM
Blocked by another task Cell PM
Cross-cell coordination Main PM (via Cell PM)
Major feature ready for CEO sign-off CEO (via escalate_to_ceo, PM/Board only)

Escalate vs Block

Action When Verb
Escalate Need a decision / help from above escalate_up
Block Can't proceed on an external dependency i_am_blocked

There is no agent-facing "pause" verb. If you need to step off a task you claimed but haven't progressed, use unclaim(task_id) to return it to the pool.

Blocking a Task

i_am_blocked(
    task_id="<task>",
    reason="Waiting for the auth service to land",
    blocker_type="external",
    what_needed="auth-service /token endpoint deployed",
)

Your Cell PM is notified and is the one who can unblock it.

CEO Escalation (Main PM / Board Only)

For major tasks requiring CEO approval:

escalate_to_ceo(
    task_id="<task>",
    reason="Major feature ready for final review",
)

Requirements:

  • Task must be in awaiting_pm_review
  • PR must exist
  • Only Main PM, Product Owner, or Head of Marketing can call it
  • PARENT TASKS ONLY — subtasks cannot be escalated to CEO

If you need to escalate a subtask, escalate the parent task instead. The CEO reviews the complete feature, not individual components.

Good Escalation Format

Include:

  • What's the issue
  • What context you have
  • Specific question
  • What you already tried
  • How it's affecting work

Handling Escalations (PM)

  1. ACK the notification: notify_ack(notification_id)
  2. Investigate: read the task, journals, and channel messages
  3. Decide, or escalate further with escalate_up
  4. Communicate the decision (say / dm / notify)
  5. Unblock if needed: unblock(task_id, reason)

CRITICAL: Verbal resolution is NOT enough. To clear a block you MUST call unblock(task_id, reason). The reason (why you are clearing the block) is recorded as your journal:decision — no separate note(scope='decision') call is required.