Time retries its own parked cards (error / stuck) instead of waiting for a human /time retry #78

Closed
opened 2026-10-17 19:22:57 +00:00 by teahubxyz · 5 comments
Owner

Depends on #93

Why. #60, #61 and #63 sat parked for a day because an error or stuck card only moves on a human /time retry. A parked card is Time's to retry, within the governor; a human should only hear about it once Time has given up. Both this card and #93 change tick(), so this one lands after it; rebase on #75's tick() if that has landed too.

Change (.github/time/time.py).

  • In tick()'s planning loop, after last is settled and the /time retry branch: elif last and last["beat"] in ("error", "stuck") and mode == "live" → count prior automatic retries on the card (beats carrying auto_retry); if fewer than TIME_AUTO_RETRY (default 1) and no open PR is linked to the card, set last = None and auto = True. A card with an open PR is left to the existing review path.
  • Carry auto through the plan tuple. On dispatch, the "working on this" beat says "Retrying on my own, resuming the branch." and both dispatch beats carry "auto_retry": true. A seat worker gets steps = int(TIME_WORKER_STEPS * 1.5) on an automatic retry: venice_work(..., steps=None) gains the kwarg and uses it in place of the env default. (Hands already resumes the card's branch, so the second pass continues the first one's work.) Follow-up, once seats.json carries tiers: the second automatic retry escalates one tier (Terra → Sol) instead of adding turns.
  • Messages: the stuck comment ends "I'll dispatch again on my own next beat; comment /time retry to force one."; the error comment ends "I'll retry on my own next beat (TIME_AUTO_RETRY times in all); comment /time retry for one more."

Tests. error with no PR → redispatched next beat, beat carries auto_retry; stuck with no PR → retried too; after one automatic retry (default) a second error waits for a human, with TIME_AUTO_RETRY=2 it tries again; stuck with an open linked PR is reviewed, not redispatched; dry-run retries nothing; a venice: worker on an automatic retry gets steps == 60 when TIME_WORKER_STEPS=40 (stub venice_work with **kw to capture it). Pop TIME_WORKER, TIME_WORKER_STEPS, TIME_AUTO_RETRY after.

CHANGELOG line under "### Added".

DONE: PR open with the code above, python3 .github/time/test_time.py green including the new checks, CI green

Depends on #93 **Why.** #60, #61 and #63 sat parked for a day because an `error` or `stuck` card only moves on a human `/time retry`. A parked card is Time's to retry, within the governor; a human should only hear about it once Time has given up. Both this card and #93 change `tick()`, so this one lands after it; rebase on #75's `tick()` if that has landed too. **Change (`.github/time/time.py`).** - In `tick()`'s planning loop, after `last` is settled and the `/time retry` branch: `elif last and last["beat"] in ("error", "stuck") and mode == "live"` → count prior automatic retries on the card (`beats` carrying `auto_retry`); if fewer than `TIME_AUTO_RETRY` (default 1) and no open PR is linked to the card, set `last = None` and `auto = True`. A card with an open PR is left to the existing review path. - Carry `auto` through the plan tuple. On dispatch, the "working on this" beat says "Retrying on my own, resuming the branch." and both dispatch beats carry `"auto_retry": true`. A seat worker gets `steps = int(TIME_WORKER_STEPS * 1.5)` on an automatic retry: `venice_work(..., steps=None)` gains the kwarg and uses it in place of the env default. (`Hands` already resumes the card's branch, so the second pass continues the first one's work.) Follow-up, once `seats.json` carries tiers: the second automatic retry escalates one tier (Terra → Sol) instead of adding turns. - Messages: the `stuck` comment ends "I'll dispatch again on my own next beat; comment `/time retry` to force one."; the `error` comment ends "I'll retry on my own next beat (TIME_AUTO_RETRY times in all); comment `/time retry` for one more." **Tests.** `error` with no PR → redispatched next beat, beat carries `auto_retry`; `stuck` with no PR → retried too; after one automatic retry (default) a second `error` waits for a human, with `TIME_AUTO_RETRY=2` it tries again; `stuck` with an open linked PR is reviewed, not redispatched; dry-run retries nothing; a `venice:` worker on an automatic retry gets `steps == 60` when `TIME_WORKER_STEPS=40` (stub `venice_work` with `**kw` to capture it). Pop `TIME_WORKER`, `TIME_WORKER_STEPS`, `TIME_AUTO_RETRY` after. CHANGELOG line under "### Added". DONE: PR open with the code above, `python3 .github/time/test_time.py` green including the new checks, CI green
Author
Owner

Follow-up from an executed independent Sol review of #75: also cover genuine budget-cap resumption, not only error/stuck. Currently a worker writes dispatched, then hits Budget; the later capped beat is filtered out of real, leaving dispatched as the last state. When allowance returns, no PR exists and it eventually becomes stuck rather than resuming immediately. Preserve the same branch/revision context and count one retry per attempt, not per receipt.

PR #75 now fixes the NEW case where another request merely holds an in-flight reservation: the waiting worker resumes in the same heartbeat when that reservation settles. It deliberately does not claim to fix true-cap recovery or cross-process reservations. Add a test for dispatch -> actual cap -> authoritative pool reset/allowance returns -> exactly one continuation, with no manual retry and no duplicate active worker. Keep the current pool's budget check; do not raise caps to make the test pass.

**Follow-up from an executed independent Sol review of #75:** also cover genuine budget-cap resumption, not only `error`/`stuck`. Currently a worker writes `dispatched`, then hits `Budget`; the later `capped` beat is filtered out of `real`, leaving `dispatched` as the last state. When allowance returns, no PR exists and it eventually becomes stuck rather than resuming immediately. Preserve the same branch/revision context and count one retry per attempt, not per receipt. PR #75 now fixes the NEW case where another request merely holds an in-flight reservation: the waiting worker resumes in the same heartbeat when that reservation settles. It deliberately does not claim to fix true-cap recovery or cross-process reservations. Add a test for dispatch -> actual cap -> authoritative pool reset/allowance returns -> exactly one continuation, with no manual retry and no duplicate active worker. Keep the current pool's budget check; do not raise caps to make the test pass.
teahubxyz added the queued label 2026-10-18 01:55:20 +00:00
time added ready and removed queued labels 2026-10-18 07:07:44 +00:00

⏱️ Time: Claude Sonnet (Anthropic) is working on this now, on branch time/card-78.

⏱️ Time: Claude Sonnet (Anthropic) is working on this now, on branch `time/card-78`. <!-- time {"beat":"dispatched","launched":true,"worker":"anthropic"} -->

⏱️ Time: sonnet opened PR #132 (23 steps, claude-sonnet-5-5). Review and landing follow on the next beat.

⏱️ Time: `sonnet` opened PR #132 (23 steps, claude-sonnet-5-5). Review and landing follow on the next beat. <!-- time {"beat":"dispatched","worker":"anthropic","pr":132,"steps":23,"seat":"sonnet","model":"claude-sonnet-5-5"} -->

⏱️ Time: PR #132 is up for this card. haiku reviewed it on the PR.

⏱️ Time: PR #132 is up for this card. `haiku` reviewed it on the PR. <!-- time {"beat":"pr","pr":132,"launched":false,"seat":"haiku","as":"seat","review":"venice","seats":["haiku"]} -->
time closed this issue 2026-10-18 07:17:33 +00:00

⏱️ Time: approved and green, merged PR #132. Card done.

⏱️ Time: approved and green, merged PR #132. Card done. <!-- time {"beat":"merged","pr":132} -->
Sign in to join this conversation.
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: teahubxyz/time#78