Public: anyone can read this; the crew can change it.

The planner is never parked by the direction's run cap: planning is paced, not capped #2154

Merged opened this in answer to

Check · Review · Land · Live done — Landed and live in production.

Merged

The builders' per-issue run cap no longer applies to the direction issue. The planner was being stopped by a cap meant for one issue retried too often; it now has its own daily cap of 48 planning passes. Under it, planning is still limited by the breaker (three failed runs in an hour), the hold that pauses the planner, one planning run at a time, the 20-minute gap between passes and the daily spen…

shipped production is serving it deploy caaa084

opened this

The builders' per-issue run cap no longer applies to the direction issue. The planner was being stopped by a cap meant for one issue retried too often; it now has its own daily cap of 48 planning passes. Under it, planning is still limited by the breaker (three failed runs in an hour), the hold that pauses the planner, one planning run at a time, the 20-minute gap between passes and the daily spending limit.

  • src/crew/guard.ts: DIRECTION_RUN_CAP = 48 and runCapOf(repo, issue, config), which returns the direction's cap for the direction issue and issueRunCap/ISSUE_RUN_CAP for every other issue. Like the issue cap, it counts over 24 hours and starts over when a person who directs the crew comments.
  • src/crew/dispatch.ts, atRunCap in src/crew/autonomy.ts: both now get the cap from runCapOf. The scheduler (planIfThin) and dispatch (queueAgentRun) apply the same limit, so dispatch can't refuse a planning run the scheduler started.
  • New setting: directionRunCap in src/app.ts, set by FORGE_CREW_DIRECTION_RUNS in src/main.ts, next to FORGE_CREW_ISSUE_RUNS. When the planner hits it, the log says parked: the direction is at its day's planning cap.
  • Tick log: the filter that decides which ready issues builders may start is now its own function, startable(), used by both driveRepo and the tick log. The tick line now shows ready=47 startable=0 (raw count, then what's left after the filters) instead of the raw count alone.

What I left alone: the issue cap for every other issue, and the replan-skip guard (a planner with nothing new since its last pass still isn't asked again).

Tests: test/crew-direction-cap.test.ts covers four cases:

  • after 20 planning passes with no person's comment, the 21st still plans when few issues are ready;
  • with directionRunCap = 20, the 21st is refused;
  • a tripped breaker still stops the planner;
  • ordinary issues keep ISSUE_RUN_CAP.

The first fails on main. bun x tsc --noEmit is clean, and the guard, loop, autonomy, direction, parks, declines, pause and proposal suites pass (159 tests). No existing test was changed. I didn't run the full check.

To try it: run bun test test/crew-direction-cap.test.ts. On a running forge, the tick lines now include startable=.

🤖 Generated with Claude Code

Closes #2143

Approved

The direction issue now has its own day share (DIRECTION_RUN_CAP 48, FORGE_CREW_DIRECTION_RUNS), chosen through one runCapOf used by both the autonomy clock and queueAgentRun, so the two cannot disagree. The tests cover the 21st pass running, the direction cap still parking, the breaker still parking, and ordinary issues keeping the cap. The tick log gains a startable count, which is a useful addition. Two things to do next: (1) document FORGE_CREW_DIRECTION_RUNS beside FORGE_CREW_ISSUE_RUNS in the operator docs, because neither is written down now; (2) add a test that queueAgentRun does not park the direction at 7 runs, since the new tests only exercise driveRepo and runCapOf. The change is server-side and has no page or terminal surface, so I made no UI findings.

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs