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".
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>
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 main2026-10-18 07:17:33 +00:00
time
deleted branch time/card-782026-10-18 07:17:33 +00:00
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
An
errororstuckcard with no open PR is now dispatched again on the next beat, up toTIME_AUTO_RETRYtimes (default 1; 0 leaves it to a human). It no longer waits for/time retry.tick()/time retrybranch, anelif last["beat"] in ("error", "stuck") and mode == "live"branch setslast = Noneandauto = True. It does this only while prior automatic retries are belowTIME_AUTO_RETRYand no open PR is linked to the card.autois carried through the plan tuple.auto_retry: true. So does the Cursor dispatch beat, and so does theerrorbeat of an automatic attempt.auto_retrybeats. 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 getsint(TIME_WORKER_STEPS * 1.5).stepsis passed only on an automatic retry, so existingvenice_workstubs without the kwarg still work.stuckanderrorcomments 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.jsoncarrying tiers.Tests (
test_time.py, new section 78)errorwith no PR is redispatched and the beat carriesauto_retry.stuckwith no PR is retried too.errorwaits for a human. WithTIME_AUTO_RETRY=2it tries again./time retrystill works after the automatic retries are spent.stuckwith an open linked PR is reviewed, not redispatched. A closed PR doesn't block the retry.errorcomment from a failing Cursor launch.venice:worker on an automatic retry getssteps == 60whenTIME_WORKER_STEPS=40. A first dispatch gets none.TIME_WORKER,TIME_WORKER_STEPSandTIME_AUTO_RETRYare 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 resetsTIME_AUTO_RETRYbetween checks.python3 .github/time/test_time.pypasses 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
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_usedcounts runs of consecutiveauto_retrybeats, 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 retrybranch 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:stepsis passed only on an automatic retry, so existingvenice_workstubs keep working.revandautocan't both be set, since auto requires no open PR.time.py:1477-1478and1491-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 setTIME_AUTO_RETRY=0, which is the right change for those cases.Non-blocking:
time.py:1476: astuckcard 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.pyends with an added blank line. Trivial.review by haiku · claude-haiku-5-5 · via Time