You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Cursor's economics work shows unbounded swarms are how you get a $10k run. Once Factory has a per-run cost ledger (#185), the next lever is a budget it actually enforces. The TeamSpectokenBudget / timeBudgetSeconds fields exist upstream but are parsed and never enforced by a live executor. This makes a run's cost/time budget a real gate: exceed it and the run is parked for human review, not silently overspent.
Goal
Add a configurable per-run token + USD + wall-time budget; when a run's accumulated spend (from the #185 ledger) crosses the budget, stop dispatching further work, park the issue with a clear reason, and emit a bounded event — never a silent overspend, never a hard crash mid-writeback.
What to build
Budget config in src/config/schema.ts: budget: { maxUsd?, maxTokens?, maxWallSeconds?, onExceed: 'park' | 'halt' } (default park), with sane repo-level defaults and per-run override.
On exceed: stop new dispatch/spawn for that run, transition the issue to a parked/human-review state with a bounded run.budget.exceeded.v1 event (role/model/usd/tokens/limit only — allowlist), and post the reason via the existing writeback path. In-flight agents finish their current step; no partial-writeback corruption.
Fail-open on missing price data: an unpriced run (usd null) must fall back to the token/time budget, and if none is set, must not block (log a bounded budget.unpriced.skipped event).
Acceptance
Budget config parsed + validated; onExceed defaults to park.
Crossing maxUsd / maxTokens / maxWallSeconds parks (or halts) the run and stops further dispatch.
A bounded run.budget.exceeded.v1 event is emitted; the reason is written back to the issue/PR thread.
Unpriced runs fall back to token/time budget and never hard-block on missing price.
"Compiles" is not done. Run a lifecycle that deliberately blows the budget on the fake fleet and observe the run park with a written-back reason — then check the harness in.
Run it
npm run build
npm run featuremap:check
npm test
npm run verify:e2e
The E2E (test/e2e/run-budget-gate.test.ts) must:
Configure a tiny maxUsd; drive a run on the in-process fake fleet whose synthetic usage exceeds it.
Assert further dispatch/spawn stops after the crossing, the issue is parked, and exactly one run.budget.exceeded.v1 bounded event fires with allowlisted attributes only.
Assert a within-budget run completes normally with no budget event (no false trip).
Assert an unpriced run with only maxTokens set trips on tokens; with no budget set, it does not block.
Deliverable
test/e2e/run-budget-gate.test.ts proving over-budget parks and within-budget passes, one command.
Fails loudly if an over-budget run keeps dispatching or if a within-budget run trips (no false green).
Blocked by: #185
Motivation
Cursor's economics work shows unbounded swarms are how you get a $10k run. Once Factory has a per-run cost ledger (#185), the next lever is a budget it actually enforces. The
TeamSpectokenBudget/timeBudgetSecondsfields exist upstream but are parsed and never enforced by a live executor. This makes a run's cost/time budget a real gate: exceed it and the run is parked for human review, not silently overspent.Goal
Add a configurable per-run token + USD + wall-time budget; when a run's accumulated spend (from the #185 ledger) crosses the budget, stop dispatching further work, park the issue with a clear reason, and emit a bounded event — never a silent overspend, never a hard crash mid-writeback.
What to build
src/config/schema.ts:budget: { maxUsd?, maxTokens?, maxWallSeconds?, onExceed: 'park' | 'halt' }(defaultpark), with sane repo-level defaults and per-run override.CostLedger): after each recorded usage, compare the run aggregate against the budget.run.budget.exceeded.v1event (role/model/usd/tokens/limit only — allowlist), and post the reason via the existing writeback path. In-flight agents finish their current step; no partial-writeback corruption.null) must fall back to the token/time budget, and if none is set, must not block (log a boundedbudget.unpriced.skippedevent).Acceptance
onExceeddefaults topark.maxUsd/maxTokens/maxWallSecondsparks (or halts) the run and stops further dispatch.run.budget.exceeded.v1event is emitted; the reason is written back to the issue/PR thread.catalog.feature_count/tier_countsbump) sofeaturemap:checkstays green.✅ End-to-end verification — Factory success criteria (REQUIRED)
"Compiles" is not done. Run a lifecycle that deliberately blows the budget on the fake fleet and observe the run park with a written-back reason — then check the harness in.
Run it
npm run build npm run featuremap:check npm test npm run verify:e2eThe E2E (
test/e2e/run-budget-gate.test.ts) must:maxUsd; drive a run on the in-process fake fleet whose synthetic usage exceeds it.run.budget.exceeded.v1bounded event fires with allowlisted attributes only.maxTokensset trips on tokens; with no budget set, it does not block.Deliverable
test/e2e/run-budget-gate.test.tsproving over-budget parks and within-budget passes, one command.Anchor files
src/cost/ledger.ts(from Cost & token accounting for every run: per-role, per-model ledger surfaced on completion #185 — subscribe to usage updates)src/orchestrator/factory.ts(dispatch/spawn gate; park/human-review transition; writeback)src/observability/events.ts(run.budget.exceeded.v1),src/config/schema.ts(budget config),src/index.ts.agentworkforce/features/manifest.yamlfactory-test-infra: Cloudflare-based ephemeral verification environments (Workers for Platforms + Containers) + factory provider wiring #146 (env cost/time budget), concurrency caps insrc/config/schema.tsOut of scope
Related