Worker: build where the card says (Base: <branch>), finish what it starts (the cap gates launches), oldest card first #118

Closed
teahubxyz wants to merge 3 commits from ceo/worker-base-and-slack into main
pull from: ceo/worker-base-and-slack
Owner

Two gaps in the worker loop that today's wave exposed, and one ordering fix.

Base: <branch> in a card. Every worker branched from main whatever the card said, and the ventures live on gh-pages (an orphan branch, no shared history). That is why #60 and #63 ran out of turns, #95 died at 43 steps and #109 opened the right files against the wrong branch. Now card_base() reads a Base: <branch> line; Hands cuts the branch from it (git_commit(..., base=)), names it time/card-N-<base> so a stale branch cut from main is never resumed, the worker's rules say where the files live, and open_pr targets the base. Cards without the line are unchanged (time/card-N, default branch).

A launched worker finishes. budget_check() gains a slack that only applies inside finishing(): the worker's model calls and the review of a PR that is already open may run past the daily cap, up to TIME_CAP_SLACK x it (default 1.5). A new launch is still refused at the cap, and the monthly cap is hard everywhere. #87's run was launched at $3.80 and stopped at step 27 when the cap crossed, its spend lost; the reviews of #109/#110 sat unreviewed for the same reason. TIME_CAP_SLACK=1 is the old behaviour. The doctor lists the knob.

Oldest ready card first. tick() sorts cards by number, the order promote_next already uses, instead of the newest-first the API returns.

Tests: 14b (base, branch name, PR target, the rules' wording, card_base parsing) and 57 (the run finishes under the slack; TIME_CAP_SLACK=1 stops it; a new launch gets no slack; the monthly cap stops a run; a review runs at $6 of $5 and is refused at $8; oldest first). Suite: ALL OK 57 locally with the fake World; CI runs the same.

Closes #117

🤖 Generated with Claude Code

https://claude.ai/code/session_017K4vyY3yUD3GsvoZaAtKkD

Two gaps in the worker loop that today's wave exposed, and one ordering fix. **`Base: <branch>` in a card.** Every worker branched from `main` whatever the card said, and the ventures live on `gh-pages` (an orphan branch, no shared history). That is why #60 and #63 ran out of turns, #95 died at 43 steps and #109 opened the right files against the wrong branch. Now `card_base()` reads a `Base: <branch>` line; `Hands` cuts the branch from it (`git_commit(..., base=)`), names it `time/card-N-<base>` so a stale branch cut from `main` is never resumed, the worker's rules say where the files live, and `open_pr` targets the base. Cards without the line are unchanged (`time/card-N`, default branch). **A launched worker finishes.** `budget_check()` gains a slack that only applies inside `finishing()`: the worker's model calls and the review of a PR that is already open may run past the daily cap, up to `TIME_CAP_SLACK` x it (default 1.5). A new launch is still refused at the cap, and the monthly cap is hard everywhere. #87's run was launched at $3.80 and stopped at step 27 when the cap crossed, its spend lost; the reviews of #109/#110 sat unreviewed for the same reason. `TIME_CAP_SLACK=1` is the old behaviour. The doctor lists the knob. **Oldest ready card first.** `tick()` sorts cards by number, the order `promote_next` already uses, instead of the newest-first the API returns. Tests: `14b` (base, branch name, PR target, the rules' wording, `card_base` parsing) and `57` (the run finishes under the slack; `TIME_CAP_SLACK=1` stops it; a new launch gets no slack; the monthly cap stops a run; a review runs at $6 of $5 and is refused at $8; oldest first). Suite: `ALL OK 57` locally with the fake World; CI runs the same. Closes #117 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_017K4vyY3yUD3GsvoZaAtKkD
teahubxyz added 3 commits 2026-10-18 04:25:22 +00:00
A `Base: <branch>` line in a card makes the seat worker cut its branch from that base (named time/card-N-<base>), see
that branch's files and open the PR against it: every venture card lives on gh-pages and until now the worker always
branched from main, which is why #60, #63, #95 ran out of turns and #109 targeted the wrong branch.

The daily spend cap gates launches; a run that began within budget may finish, up to TIME_CAP_SLACK x the cap (1.5),
and a PR already open gets its review on a capped day too (#87's run was stopped at step 27 with the spend lost). The
monthly cap stays hard. The tick takes the oldest ready card first, as promote_next does.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017K4vyY3yUD3GsvoZaAtKkD
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017K4vyY3yUD3GsvoZaAtKkD
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017K4vyY3yUD3GsvoZaAtKkD
Author
Owner

Superseded by #121: the same change re-cut from main after #110 and #116 landed (this branch collided with #116's change to review()). Closing.

Superseded by #121: the same change re-cut from main after #110 and #116 landed (this branch collided with #116's change to `review()`). Closing.
teahubxyz closed this pull request 2026-10-18 04:46:05 +00:00

Pull request closed

Please reopen this pull request to perform a merge.
Sign in to join this conversation.