Skip to content

[coordination] Autonomous work budget — bound spend across every unattended entry point #184

Description

@serge-ivo

Design: docs/supervision.md. Companion to #183. Revised after critical review — the first draft was wrong in three ways, recorded below.

Why

Nothing in the platform enforces a spend cap. ai_usage (migration 0048) records cost_micros faithfully, but it is a ledger, not a control — it tells you what a runaway cost you, after it cost you. The only limits in the codebase are req/min rate limits, which bound request frequency, not spend.

Two levels of hierarchy in code are safe because a human wrote them. N levels by configuration are not. Fan-out 5 at 3 levels is 125 leaf runs from one delegation, each an LLM call.

Three corrections to the original draft

1. Depth bounds almost nothing. The first draft leaned on depth as a primary control. It is not: a supervisor at depth 1 can re-delegate sequentially a thousand times without ever increasing depth. Depth caps tree height; it does not cap work. Keep it as a cheap per-path guard, but cost is the real control, plus a separate delegation-count guard (a cheap model can spin thousands of iterations before a cost budget bites).

2. "Carries a budget, decremented at every hop" is wrong under fan-out. That describes a value copied down each path — so five siblings each receive the full allowance and the tree total becomes allowance × fanout^depth, i.e. unbounded in exactly the quantity we are trying to bound. It must be a shared pool scoped to the root delegation, drawn from atomically (UPDATE … SET remaining = remaining - ? WHERE remaining >= ?), not a per-path copy.

3. Check-then-go overshoots under concurrency. Cost is only known after a run. An optimistic "is there budget left?" check lets N concurrent branches all pass simultaneously and overshoot by N × run_cost. This is the classic overbooking problem. Correct pattern: reserve a bounded maximum before starting, settle the actual on completion, refund the remainder.

Scope correction: budget every autonomous entry point, not just delegation

Supervision makes this acute but did not create it. Today every unattended path starts work with no budget:

Budgeting only delegation plugs one hole in a boat. This should be one primitive covering all four, with delegation as the first consumer.

Retries and replay must draw from the same pool. The 0058 outbox retries up to 5 times with backoff, and each retry re-runs the action — so a persistently failing consumer can cost 5× before dead-lettering. Manual replay is currently unlimited. Both must check and draw.

Two pools, different purposes

Natural chokepoint for both: the BYOK/Workers-AI call path that already writes ai_usage.

Scope

  • Root-scoped budget pool: remaining cost (micros) + remaining delegations + max depth.
  • Atomic reserve-and-settle at the model-call chokepoint; refund unused reservation on completion.
  • Admission check at every autonomous entry point (cron, webhook, delivery, delegation) and on retry/replay.
  • Per-user/period backstop in addition to the per-tree pool — a tree budget alone does not stop a thousand small runaway trees.
  • Exhaustion is a distinct, visible outcome recording where it stopped ("budget exhausted at depth 3"), and must preserve the partial work as resumable once the human raises the limit. Exhaustion must not destroy what was already paid for.

Acceptance

  • Total spend across an entire delegation tree is bounded by the root pool, regardless of fan-out.
  • Concurrent siblings cannot collectively overshoot the pool.
  • A supervisor cannot raise its own budget by delegating (the pool only ever decreases).
  • Sequential re-delegation at constant depth is bounded by the cost/count budget.
  • Retries and replays draw from the pool.
  • Exhaustion surfaces its own status and the work resumes after a raise.
  • Tests: fan-out overshoot, concurrent draw, sequential re-delegation, retry drain, resume-after-raise.

Note

Build this with #183. Threading a budget through an existing handoff path is a retrofit touching every call site; adding it while the path is being defined is nearly free.

Metadata

Metadata

Assignees

No one assigned

    Labels

    backendBackend / Worker / API workcoordinationAgent coordination / delegation primitivessecuritySecurity hardening / audit finding

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions