Time retries its own parked cards (error / stuck) #132

Merged
time merged 6 commits from time/card-78 into main 2026-10-18 07:17:33 +00:00
Collaborator

An error or stuck card with no open PR is now dispatched again on the next beat, up to TIME_AUTO_RETRY times (default 1; 0 leaves it to a human). It no longer waits for /time retry.

tick()

  • After the /time retry branch, an elif last["beat"] in ("error", "stuck") and mode == "live" branch sets last = None and auto = True. It does this only while prior automatic retries are below TIME_AUTO_RETRY and no open PR is linked to the card.
  • A card with an open PR is left to the existing review path.
  • auto is carried through the plan tuple.
  • Both seat dispatch beats carry auto_retry: true. So does the Cursor dispatch beat, and so does the error beat of an automatic attempt.
  • The "working on this" beat adds "Retrying on my own, resuming the branch."
  • Prior retries are counted as runs of consecutive auto_retry beats. One automatic retry writes up to three beats (the launch, the result or the error), so counting every flagged beat would count it two or three times. An attempt that fails before it launches still counts, so a persistently failing card can't retry every beat forever.
  • venice_work(..., steps=None) takes the new kwarg and uses it instead of the env default. On an automatic retry a seat worker gets int(TIME_WORKER_STEPS * 1.5). steps is passed only on an automatic retry, so existing venice_work stubs without the kwarg still work.
  • The stuck and error comments end with the wording from the card.

Message choice you may want to change: when the retry budget is spent, or in dry-run, the new tail would be false. In those cases the comments keep the old "Comment /time retry …" tail.

Not done: the tier-escalation follow-up. It waits on seats.json carrying tiers.

Tests (test_time.py, new section 78)

  • error with no PR is redispatched and the beat carries auto_retry.
  • stuck with no PR is retried too.
  • After one automatic retry a second error waits for a human. With TIME_AUTO_RETRY=2 it tries again.
  • A seat's two dispatch beats plus its error count as one retry.
  • A human /time retry still works after the automatic retries are spent.
  • stuck with an open linked PR is reviewed, not redispatched. A closed PR doesn't block the retry.
  • Dry-run retries nothing.
  • Both messages are checked, including the error comment from a failing Cursor launch.
  • A venice: worker on an automatic retry gets steps == 60 when TIME_WORKER_STEPS=40. A first dispatch gets none.
  • TIME_WORKER, TIME_WORKER_STEPS and TIME_AUTO_RETRY are popped afterwards.

Two existing checks, 5b and 7b, parked a card and expected it to stay put. They now set TIME_AUTO_RETRY=0. run() also resets TIME_AUTO_RETRY between checks.

python3 .github/time/test_time.py passes locally, including "ALL OK 78". I did not run the venture tests (TIME_TEST_VENTURE=1). I haven't seen CI run on the PR yet. The CHANGELOG line is under "### Added".

Closes #78

worker: Claude Sonnet (Anthropic) via Time

An `error` or `stuck` card with no open PR is now dispatched again on the next beat, up to `TIME_AUTO_RETRY` times (default 1; 0 leaves it to a human). It no longer waits for `/time retry`. **`tick()`** - After the `/time retry` branch, an `elif last["beat"] in ("error", "stuck") and mode == "live"` branch sets `last = None` and `auto = True`. It does this only while prior automatic retries are below `TIME_AUTO_RETRY` and no open PR is linked to the card. - A card with an open PR is left to the existing review path. - `auto` is carried through the plan tuple. - Both seat dispatch beats carry `auto_retry: true`. So does the Cursor dispatch beat, and so does the `error` beat of an automatic attempt. - The "working on this" beat adds "Retrying on my own, resuming the branch." - Prior retries are counted as runs of consecutive `auto_retry` beats. One automatic retry writes up to three beats (the launch, the result or the error), so counting every flagged beat would count it two or three times. An attempt that fails before it launches still counts, so a persistently failing card can't retry every beat forever. - `venice_work(..., steps=None)` takes the new kwarg and uses it instead of the env default. On an automatic retry a seat worker gets `int(TIME_WORKER_STEPS * 1.5)`. `steps` is passed only on an automatic retry, so existing `venice_work` stubs without the kwarg still work. - The `stuck` and `error` comments end with the wording from the card. **Message choice you may want to change:** when the retry budget is spent, or in dry-run, the new tail would be false. In those cases the comments keep the old "Comment `/time retry` …" tail. **Not done:** the tier-escalation follow-up. It waits on `seats.json` carrying tiers. **Tests (`test_time.py`, new section 78)** - `error` with no PR is redispatched and the beat carries `auto_retry`. - `stuck` with no PR is retried too. - After one automatic retry a second `error` waits for a human. With `TIME_AUTO_RETRY=2` it tries again. - A seat's two dispatch beats plus its error count as one retry. - A human `/time retry` still works after the automatic retries are spent. - `stuck` with an open linked PR is reviewed, not redispatched. A closed PR doesn't block the retry. - Dry-run retries nothing. - Both messages are checked, including the `error` comment from a failing Cursor launch. - A `venice:` worker on an automatic retry gets `steps == 60` when `TIME_WORKER_STEPS=40`. A first dispatch gets none. - `TIME_WORKER`, `TIME_WORKER_STEPS` and `TIME_AUTO_RETRY` are popped afterwards. Two existing checks, 5b and 7b, parked a card and expected it to stay put. They now set `TIME_AUTO_RETRY=0`. `run()` also resets `TIME_AUTO_RETRY` between checks. `python3 .github/time/test_time.py` passes locally, including "ALL OK 78". I did not run the venture tests (`TIME_TEST_VENTURE=1`). I haven't seen CI run on the PR yet. The CHANGELOG line is under "### Added". Closes #78 <sub>worker: Claude Sonnet (Anthropic) via Time</sub>
time added 6 commits 2026-10-18 07:10:07 +00:00
card #78: kept .github/time/time.py (generated)
time/worker-run python3 - <<'EOF' p = ".github/time/time.py" s = open(p).read() old = 'f"I\'ll retry on my own next
790c6d6eac
card #78: kept .github/time/time.py (generated)
time/worker-run python3 - <<'EOF' p = ".github/time/test_time.py" s = open(p).read() old = '"TIME_REQUIRE_CHECKS", "
5c46d27564
card #78: kept .github/time/test_time.py (generated)
time/worker-run python3 - <<'EOF' p = ".github/time/test_time.py" s = open(p).read() i = s.index("\n\n# 78 Time retr
4a41ff3063
card #78: kept .github/time/test_time.py (generated)
time/worker-run python3 - <<'EOF' import re p = ".github/time/test_time.py" s = open(p).read() i = s.index("# 78 Tim
4352afc49a
card #78: kept .github/time/test_time.py (generated)
time/worker-run python3 - <<'EOF' p = "CHANGELOG.md" s = open(p).read() h = "### Added\n" i = s.index(h) + len(h) li
8ee49f048f
card #78: kept CHANGELOG.md (generated)
ci / test (pull_request) Successful in 35s
heartbeat / tick (pull_request_review) Successful in 7m57s
dde6f19f35
haiku approved these changes 2026-10-18 07:10:30 +00:00
haiku left a comment
Collaborator

Approve, with one caveat: the DONE line requires CI green, and ci / test (pull_request) is still pending, so this isn't mergeable until that passes. I didn't run the tests myself. The review is from the diff and the PR description.

Checked and fine:

  • time.py:1350-1372: auto_used counts runs of consecutive auto_retry beats, so one automatic retry (launch, result, error) counts once. Failed launches still count, so a persistent failure can't retry every beat.
  • time.py:1371-1373: the auto branch sits after the /time retry branch and only fires in live mode with no open linked PR. A card with an open PR still goes to review.
  • time.py:1431-1436: steps is passed only on an automatic retry, so existing venice_work stubs keep working. rev and auto can't both be set, since auto requires no open PR.
  • time.py:1477-1478 and 1491-1493: the stuck and error messages match the card. The error message counts the current attempt (+ (1 if auto else 0)), so the "one more" wording is correct on the last allowed try.
  • test_time.py:837-892: the section covers the cases the card asks for, plus the one-retry-per-run counting and dry-run. Tests 5b and 7b now set TIME_AUTO_RETRY=0, which is the right change for those cases.

Non-blocking:

  • time.py:1476: a stuck card can be redispatched while the first Cursor agent may still be running, and that could produce a second PR for the same card. The card asks for this behaviour, so I'm only flagging the risk.
  • test_time.py ends with an added blank line. Trivial.

review by haiku · claude-haiku-5-5 · via Time

**Approve**, with one caveat: the DONE line requires CI green, and `ci / test (pull_request)` is still pending, so this isn't mergeable until that passes. I didn't run the tests myself. The review is from the diff and the PR description. Checked and fine: - `time.py:1350-1372`: `auto_used` counts runs of consecutive `auto_retry` beats, so one automatic retry (launch, result, error) counts once. Failed launches still count, so a persistent failure can't retry every beat. - `time.py:1371-1373`: the auto branch sits after the `/time retry` branch and only fires in live mode with no open linked PR. A card with an open PR still goes to review. - `time.py:1431-1436`: `steps` is passed only on an automatic retry, so existing `venice_work` stubs keep working. `rev` and `auto` can't both be set, since auto requires no open PR. - `time.py:1477-1478` and `1491-1493`: the stuck and error messages match the card. The error message counts the current attempt (`+ (1 if auto else 0)`), so the "one more" wording is correct on the last allowed try. - `test_time.py:837-892`: the section covers the cases the card asks for, plus the one-retry-per-run counting and dry-run. Tests 5b and 7b now set `TIME_AUTO_RETRY=0`, which is the right change for those cases. Non-blocking: - `time.py:1476`: a `stuck` card can be redispatched while the first Cursor agent may still be running, and that could produce a second PR for the same card. The card asks for this behaviour, so I'm only flagging the risk. - `test_time.py` ends with an added blank line. Trivial. <sub>review by haiku · claude-haiku-5-5 · via Time</sub>
time merged commit 4c91878f93 into main 2026-10-18 07:17:33 +00:00
time deleted branch time/card-78 2026-10-18 07:17:33 +00:00
Sign in to join this conversation.