Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 17 additions & 2 deletions docs/architecture/cockpit.md
Original file line number Diff line number Diff line change
Expand Up @@ -854,7 +854,9 @@ that walks it** — plus a usable completion signal, below.

**The record.** `task_supervisions` (one row per supervised umbrella: explicit
status filter, WIP limit, model, event watermark, `last_tick_at`,
`last_advance_at`, `last_hold_reason`) and `task_supervision_dispatches` (one
`last_advance_at`, `last_hold_reason`, and since mt#5137
`last_excluded_by_class` — the children the last tick withheld on their
autonomy class, each with the classifier's reasons) and `task_supervision_dispatches` (one
row per child started, unique on `(supervision_id, task_id)`). A partial unique
index on `umbrella_task_id WHERE status = 'active'` makes at-most-one-active a
database guarantee rather than a check-then-insert two concurrent callers would
Expand All @@ -878,7 +880,20 @@ takes no lock and does nothing):
`tasks.orchestrate` uses — extracted so the command an operator inspects an
umbrella with and the supervisor that dispatches from it cannot disagree
about whether a child is blocked.
4. **Dispatch up to the free WIP slots** — `resolveTaskWorkspace` →
4. **Admit on autonomy class** (mt#5137) — classify the not-yet-dispatched
frontier with `classifyTasks` (`packages/domain/src/tasks/autonomy-class-store.ts`,
the same classifier `tasks_available` consults) and keep only servable
classes (`pull-only`, `contained`). A `principal-gated` or `unknown` child
is recorded on `SupervisionAdvance.excludedByClass` and persisted to
`last_excluded_by_class`, never silently dropped; `tasks.supervision-status`
lists it under `Withheld on autonomy class (N)`. When every dispatchable
child is withheld the hold reason is `all-candidates-gated-by-autonomy-class`,
kept distinct from `all-children-blocked` so an umbrella whose remaining
work is the principal's does not read as a dependency stall. The check
sits here rather than inside `computeUmbrellaFrontier` on purpose:
`tasks.orchestrate` shares the frontier and answers an agent's own pull,
where the default-deny lands on the agent (`docs/autonomy-class.md`).
5. **Dispatch up to the free WIP slots** — `resolveTaskWorkspace` →
`startDrivenSession` → `sendDrivenSessionInput` with a prompt from
`generateSubagentPrompt`. Note this does NOT call `tasks_dispatch`, which
spawns nothing: it ends at prompt generation, gated on
Expand Down
14 changes: 13 additions & 1 deletion docs/autonomy-class.md
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,19 @@ classifier reads as incident lineage.
lands on Phase 2's pull). Membership in a pointing never overrides the
class.

Not yet wired: the unattended supervisor's child admission (mt#5137).
- **Unattended supervisor** (`tasks.supervise`, mt#4571; wired by mt#5137):
each tick classifies the frontier's dispatchable children with the same
`classifyTasks` the routing service uses and spawns only servable ones. A
withheld child is RECORDED rather than silently dropped — per tick on
`SupervisionAdvance.excludedByClass`, durably on
`task_supervisions.last_excluded_by_class`, and in `tasks.supervision-status`
under `Withheld on autonomy class (N)` with the classifier's reason strings.
When every dispatchable child is gated the hold reason is
`all-candidates-gated-by-autonomy-class`, distinct from
`all-children-blocked` (a dependency hold) so an umbrella whose remaining work is the principal's does
not read as a stall. The check lives in the tick, not in
`computeUmbrellaFrontier`: `tasks.orchestrate` shares the frontier and asks
on an agent's behalf, where the deny lands on the agent's own pull.

## EngProd proposals: the BLOCKED hack, retired

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ALTER TABLE "task_supervisions" ADD COLUMN "last_excluded_by_class" jsonb;
Loading
Loading