Repository navigation
Escalate before idle: a ladder between "decide myself" and "ask the human" #100
Copy link
Copy link
Open
Description
Proposal
Parent: autonomous-swarm (F2).
Why
Agents stop and hand to the operator with sentences like "Peer X owns blocker Y, so I
cannot continue until that is solved". The operator then talks to every session by hand.
Causes found in code:
send-peer-message.txtends: "If you cannot continue without an answer, say that to your
own user rather than asking the peer again." With "send once", "never ask whether a peer
is done" and "do not reply to a reply", the safe reading is: one message, then stop and
tell the human. Those rules exist for a real storm (hundreds of identical messages,
2026-09-18) and over-corrected.- The loop recognises empty output, plan-without-tools and repetition
(loop/continuation.ts). It has no concept of a turn that ended asking a question or
waiting on a peer, so such a turn ends the run or burns the no-progress budget. .skein/blocker.mdquarantines a stuck change while the queue continues, but nothing
tells a model to use it for "waiting on a peer", and nothing re-checks it when the peer
answers.
What Changes
- The ladder (design D3 of the epic), stated in the brief charter and the tool text:
decide from specs → ask the owner peer once with a deadline and continue other work →
ask the lead once after the deadline → record a blocker taggedneeds: team|humanand
move on → onlyneeds: humanreaches the human, as a board item. - Blocker records get structure:
.skein/blocker.mdgains front matter
(needs,waiting-on,asked-at,deadline,rung), parsed with a closed schema, so
the driver can enforce rung order and wake the item when the peer replies. - Wake, don't poll: when a member is blocked on a peer it registers a wake on that
peer's reply or idle (the existingPeerInboxdrain-on-idle and reply correlation),
plus a durable deadline timer in the loop. No "are you done?" messages. - Stop classifier in the loop: a turn that ends with no tool calls and text matching
"asking the user / waiting on a peer / cannot continue until" is classified
blocked-on-human-or-peerand answered with a bounded ladder nudge ("do not stop to ask:
apply rung N") instead of ending the run. Pure, import-free module like
loop/continuation.ts. It only ever produces a nudge, never an action. - Tool text and charter corrected so "say that to your user" is the last rung, not the
first, while keeping every anti-storm rule: one message per(item, rung), repeat guard
intact. - Plain (non-loop) sessions get the same ladder through the instruction fragment, and
the lead frame fromlead-authorityalready says "reply to the lead; do not ask your
user first".
Wake sources and the deadline timer are simplest inside a project server (one in-process
inbox, durable loop records) and degrade to the per-process versions otherwise.
Non-goals
- No automatic answer on the human's behalf for
needs: humanitems (goal ambiguity,
credentials, irreversible or never-listed actions). - No new message transport; no polling.
Impact
loop/continuation.ts (+ new loop/stop-reason.ts), loop/loop.ts iteration handling,
loop/spec-queue/* (blocker schema, wake), tool/send-peer-message.txt,
session/peers.ts charter text, peer/inbox.ts wake hook, tests.
Tasks
Phase 0: Corpus and baseline
- 0.1 Collect the stop corpus from
autonomous-swarm0.2 (real transcripts, labelled).
Include negatives: turns that end legitimately with a summary and no question. - 0.2 Failing test: a turn ending "I'll wait for peer X to resolve Y" is today treated as
neither stalled-for-a-reason nor continued (records current behaviour).
Phase 1: Blocker schema and ladder state
- 1.1 Front-matter schema for
.skein/blocker.md(needs,waiting-on,asked-at,
deadline,rung), closed, parsed at load; legacy free-text blockers still read as
needs: team. - 1.2 Observed-red tests: unknown key,
needsneither team nor human, rung out of order. - 1.3 Rung enforcement: at most one send per
(item, rung), with a positive control that
an identical second condition does not resend.
Phase 2: Stop classifier
- 2.1
loop/stop-reason.ts: pure classifier (asking-user / waiting-on-peer / done /
other), no imports fromloop.ts(cycle rule insimilarity.ts). - 2.2 Wire to iteration handling: classified stop → ladder nudge, bounded (3 per item),
then record aneeds: teamblocker and continue the queue. - 2.3 Replay the corpus: report precision/recall and false nudges per hour. Ship only if
false nudges are tolerable (decide threshold with the operator).
Phase 3: Wake instead of poll
- 3.1 Register wake on peer reply/idle via
PeerInbox; deadline timer persisted with the
loop record so a restart keeps it. - 3.2 On wake, re-check the blocker and resume the item; on deadline, perform rung L2
(one request to the lead) exactly once.
Phase 4: Text
- 4.1 Rewrite the relevant paragraph of
send-peer-message.txt; keep the storm
protections verbatim. - 4.2 Add the ladder to the crew charter (
crew-loop3.2) and the Claude Code fragment.
Phase 5: Live
- 5.1 Two members, deliberate cross-dependency: A blocked on B's change. Success: A moves
to another item, B's reply wakes A, the human is not contacted. - 5.2 Negative control:
needs: humanblocker (credentials) reaches the board and the
lead brief and does not stop the member.
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels
Activity