Skip to content

fleet-telegram backlog — lane monitoring + dangerous-approval loop

Speced 2026-07-10 as WT-60fa folded into the COMMS lane (governor RED consolidation). Owner to drain serially. Both are DEFERRED — gated on their dependencies. Do not build under RED; these are the spec of record.

1. Lane-level digest reporting (governor YELLOW+) [dep: none — pure fleet-telegram]

Today the digest reports per-worktree (one topic/row per session). Under YELLOW+ that's noisy (9 worktrees → 9 rows). Add a lane-collapsed view: - When governor tier ≥ YELLOW, group sessions by their consolidation LANE (from the worktree-consolidation policy — usage-governor/docs/worktree-consolidation.md; lanes owned by a session, members carry ABSORBED -> <lane> registry desc) and emit ONE digest row per lane (~3 rows), not per worktree. - Each lane row shows: lane name/owner, member count, and the lane's QUEUE DEPTH (backlog items the owner still has to drain). - Below YELLOW (GREEN): keep per-worktree rows. - Source of lane membership: worktree-identity registry desc field (ABSORBED -> comms lane etc.) — parse it; don't hardcode lane names.

2. Lane-cap breach alert [dep: none — pure fleet-telegram]

Immediate-push alert when live Claude session count exceeds the governor tier's lane cap: - Caps: YELLOW=5, RED=3, BLACKOUT=1 (read tier from ~/.claude/usage-governor/state.json, same GovernorGate path the digest cadence already uses). - Count live Claude sessions (adapter already enumerates them). If count > cap → immediate-push (not batched) a warning naming the over-cap sessions so the governance/ops lane can force-absorb them. - This is a monitoring signal only — fleet-telegram never kills sessions; it reports the breach.

3. DANGEROUS-class approval loop (fleet.v1) [dep: bus P4; P2 adapter must carry the approval.decision publish path from the start]

Andrew's ratified channel split (relayed via comms-bus session, to be reconfirmed at build time): Pavlok OUT (alert-only), Telegram IN (the only decision channel). Reuses existing PavlokPager + fleet-telegram inline-button paths; the bus gives them one subscription instead of bespoke wiring.

Flow: 1. Listener receives a dangerous-class command → does NOT execute. Publishes fleet.v1.approval.required { id, commandSummary, sender, target, capabilities[], riskReason }. 2. fleet-telegram (subscriber on approval.required) does TWO things: - (a) OUTBOUND ALERT: Pavlok page to Andrew (pavlok-page skill / PavlokPager CLI, vibe→beep→zap escalation). Pavlok is one-way wristband: ALERT ONLY, never carries the decision. - (b) INBOUND DECISION: Telegram message with inline approve/deny buttons + full command detail. 3. Andrew taps approve/deny in Telegram → fleet-telegram publishes fleet.v1.approval.decision.{id} { approved:bool, approver, decidedAtUtc } SIGNED with the human-authority token (the bot's sessionId-keyed key from the fleet.v1 crypto anchor). 4. Listener waits on approval.decision.{id} with a timeout → timeout OR deny = DO NOT EXECUTE; approve = execute. Default deny.

INVARIANTS (load-bearing — this is the whole injection defense): - Pavlok = alert-only (reach Andrew); Telegram = the only decision channel (Andrew→fleet). - The decision message MUST be signed or the listener rejects it — else a spoofed approval.decision auto-approves, which is the injection hole the human gate exists to close. - Default deny on timeout. Dangerous class is NEVER auto-executed regardless of trust tier or taint state. - P2 carry-forward: when the fleet-telegram ISessionAdapter swaps to a bus subscription at P2, build the approval.decision publish path (signed, sessionId-keyed) into the seam from the start so P4 is wiring, not a rebuild.

Cross-refs: fleet.v1 envelope = memory fleet-bus-envelope-fleetv1.md; trust tiers (data/command/dangerous + taint demotion) settled by the comms-bus council. This approval loop is the DANGEROUS tier's human gate.