Repository navigation
[coordination] Ticket 1 — subordinate_status: give the Lead a global picture #205
Description
Problem
coder-lead supervises N coder-repo instances through agent_supervision (#183) — the Overseer moved up a level, which is the design. But the Lead is not yet as capable as the thing it replaces.
The hardcoded Overseer (routes/coding.ts ~1085) opens by building a global picture — for every repo: is a session live, what did it last print, what are its instructions — then answers from it in one model call, or delegates. That answering half is what makes it an overseer.
list_subordinates returns {instanceId, name, status}, and status is agent_instances.status — the subscription lifecycle (active|paused|canceled), permanently "active" whether a subordinate is idle, mid-run, or on fire. So the Lead must delegate a run (durable workflow + full LLM loop) to learn anything.
This is a wrong field on a read path, not a missing abstraction.
Decision: compose, do not unify
Rejected: widening agent_loop_runs with a kind discriminator so pipeline/apply/browse/coding runs share one table.
- "Idle" and "stuck" are not rows. Idle is the absence of a row; stuck is a derivation over timestamps + runner liveness. A resolver is needed either way — the composition is irreducible, the table merge is not. That inverts the build order.
- Four lifecycle records, not three. A human-driven coding session writes only
coding_sessions— and that is the Lead's main case. Akindover the three named tables misses the row it most needs. - A
kindenum is a second closed enum, in D1 where it is harder to change, while [coordination][deferred] Retire the workflow closed enum → declarative behavior #160 is retiring the first. - Measured cost. The one partial unification already done (
delegateToPilotwriting a loop row) shipped two stranded-row bugs, both memorialised incoding-session.ts:122and:158. Unifying adds ~5 open and ~20 terminal sites, and a stranded row is permanent data — unlike a read bug, which a redeploy fixes. - It fails the docs' own test (
coordination-primitives.md: "Build the abstraction when the fix you'd make anyway can be made through it"). The fix you'd make anyway is a status read, and it cannot be made through the unified table — it would be blocked behind five write-path conversions before producing one correct answer.
The staged gate for revisiting: a second consumer needs cross-instance run pagination that an in-memory merge cannot serve, and the reader is measured as the bottleneck. A read-only SQL VIEW union is the correct intermediate, and probably the terminal state.
The rule this must not break
Connectors read generic platform tables or a declared per-instance setting — never a domain store. Precedent: lib/connectors/repo-local.ts:35-51 stays generic by reading config.settings["repo_path"] rather than importing coding-store. lib/delegation.ts:8-27: "Generic so the board card doesn't have to be re-shaped per target kind."
The domain writes into a generic record; the supervisor reads platform records. A first attempt made lib/connectors/supervision.ts import coding-store/coding-timeline — reverted in 3f14bd3, because that is exactly the coupling migration 0063 says was removed.
The enabler
capabilities.boardColumns is already a declared, per-agent status vocabulary ({id,title,statuses[]}), resolved by boardConfigForInstance (lib/board.ts:33). A supervisor normalises any subordinate's free-text status through the subordinate's own declaration — no new declaration surface, and a third-party agent with columns "Triage / Cooking / Shipped" works on day one.
Two vocabularies, handled differently — this distinction is the design:
instance_runtime_tasks.statusis free text → bucketed through the subordinate's declared columns; output carries both the raw status and that agent's owncolumnTitle.agent_loop_runs.statusis a closed platform enum → passed through verbatim, never bucketed.
Scope
columnForStatusinlib/agent-capabilities.ts. The rule exists twice already, both outside the API and both also matchingcolumn.id === status:store/console/src/tabs/BoardTab.tsx:636andworkers/mcp/src/instance-tools/shared.ts:87. Point the MCP copy at the new canonical one.lib/instance-work.ts(new) —recentWorkForInstances/recentRunsForInstances. One D1 statement each, aUNION ALLof one indexed branch per subordinate (a flatIN (…) ORDER BY … LIMIT nlets one busy subordinate crowd out eleven). Must filterhidden = 0(0019) or cleared cards resurface. Guard the empty-id case — an emptyUNION ALLis a syntax error and a Lead with no links is reachable.lib/subordinate-observation.ts(new) — pure, no D1. Bucketing, staleness, and the 16 000-char cap (the ceiling the Overseer itself uses).lib/agent-loop-store.ts—last_progress_at, written byrecordIterationvia a defaulted arg soAgentLoopWorkflowstarts reporting progress with no change.check_delegationimproves for free.lib/connectors/supervision.ts— addsubordinate_status(read); renamelist_subordinates' misleadingstatus→subscription; intersect anyinstanceIdargument with the graph.agent-think.ts— add toREAD_ONLY_TOOLS, or the cross-round dedup refuses the Lead's second observation in a turn.- Migration
0067— the column, plusjson_seton thecoder-leadtemplate's declared tools. No per-instance backfill:agentCapabilitiesresolves fromagents.configat read time, so every subscribed Lead picks it up.
Read-only feature: it writes nothing, so no row can be stranded by it.
Acceptance
Ask the Lead "what is each of your agents doing right now?" — it answers from one subordinate_status call with zero delegate_goal calls.
Depth is deliberately outcomes + progress (objective, running/needs-you/done, step 4/10, quiet-for-N-min, outcome text), not raw terminal. The honest equivalent of the Overseer's terminal tail is deferred to #207.
Activity
Revert "feat(coordination): give the Lead the global picture — it was…
serge-ivo commentedon Aug 4, 2026
Reverted (3f14bd3). Building this was premature, and the implementation proved the point: it made the GENERIC supervision connector import
coding-storeandcoding-timeline— the same "a route that knows about repos" coupling 0063 says was removed. Reopening as a design question to settle before any code.[-][coordination] The Coder Lead is a dispatcher, not an Overseer — it has no global picture[/-][+][coordination] Ticket 1 — subordinate_status: give the Lead a global picture[/+]fix(coordination): answer the question through the tool the model act…
feat(coordination): pipeline cards, a live progress line, and a sweep…
feat(supervision): a delegated run now records what it DID, not just …