Cards adopt an open PR that already closes them: review and land it instead of dispatching a worker #93

Closed
opened 2026-10-18 01:17:32 +00:00 by teahubxyz · 10 comments
Owner

Why. Work built outside Time's worker — Codex's #75 (acceptance card #84), #69, #70, and any PR a seat opens from a chat — cannot enter Time's review-and-landing path: tick() only reviews PRs it dispatched a worker for, and a ready card with no beats would launch a worker to build the thing again. So externally built PRs wait for a human merge, which is the last place a human sits in the loop.

Change (.github/time/time.py, tick()). For a ready card with no real beats (state None), before dispatching: look for an open PR whose body closes the card (linked_prs()). If one exists, adopt it: post the pr beat ({"beat": "pr", "pr": N, "adopted": true}) and run review() on it in the same tick, exactly as if a worker had opened it. The next beats then land it through land() on Approve + green like any other card PR — engine paths included, since TIME_PROTECTED now allows them. No launch is counted, no worker budget is spent; the review books to the ledger as usual. A ready card whose body says PR: #N explicitly is adopted the same way even when the PR body lacks Closes #N. In dry-run the beat says what it would adopt.

Tests. A ready card with an open PR closing it → pr beat with adopted, a review posted, no worker launched, launches_today unchanged; the same card with TIME_AUTOMERGE=on, an Approve and green checks → merged on the next tick; a ready card with no PR → dispatched as today; a closed PR is not adopted; PR: #N in the body adopts without Closes.

CHANGELOG line under "### Added". Once this lands, #84 labelled ready puts #75 through haiku's review and time's merge with no hand on it.

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

**Why.** Work built outside Time's worker — Codex's #75 (acceptance card #84), #69, #70, and any PR a seat opens from a chat — cannot enter Time's review-and-landing path: `tick()` only reviews PRs it dispatched a worker for, and a `ready` card with no beats would launch a worker to build the thing again. So externally built PRs wait for a human merge, which is the last place a human sits in the loop. **Change (`.github/time/time.py`, `tick()`).** For a `ready` card with no real beats (state `None`), before dispatching: look for an open PR whose body closes the card (`linked_prs()`). If one exists, adopt it: post the `pr` beat (`{"beat": "pr", "pr": N, "adopted": true}`) and run `review()` on it in the same tick, exactly as if a worker had opened it. The next beats then land it through `land()` on Approve + green like any other card PR — engine paths included, since `TIME_PROTECTED` now allows them. No launch is counted, no worker budget is spent; the review books to the ledger as usual. A `ready` card whose body says `PR: #N` explicitly is adopted the same way even when the PR body lacks `Closes #N`. In dry-run the beat says what it would adopt. **Tests.** A `ready` card with an open PR closing it → `pr` beat with `adopted`, a review posted, no worker launched, `launches_today` unchanged; the same card with `TIME_AUTOMERGE=on`, an Approve and green checks → merged on the next tick; a `ready` card with no PR → dispatched as today; a closed PR is not adopted; `PR: #N` in the body adopts without `Closes`. CHANGELOG line under "### Added". Once this lands, #84 labelled `ready` puts #75 through haiku's review and `time`'s merge with no hand on it. DONE: PR open with the code above, `python3 .github/time/test_time.py` green including the new checks, CI green
teahubxyz added the ready label 2026-10-18 01:54:41 +00:00

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

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

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

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

⏱️ Time: today's spend is $5.01 of the $5.00 cap; carrying on tomorrow. Nothing is lost; this card resumes once there is budget.

⏱️ Time: today's spend is $5.01 of the $5.00 cap; carrying on tomorrow. Nothing is lost; this card resumes once there is budget. <!-- time {"beat":"capped"} -->

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

⏱️ Time: PR #110 is up for this card. `haiku` reviewed it on the PR. <!-- time {"beat":"pr","pr":110,"launched":false,"review":"venice","seat":"haiku"} -->

⏱️ Time: the reviewer objected on PR #110. Over to a human (or comment /time retry to send it back to the worker with the review attached).

⏱️ Time: the reviewer objected on PR #110. Over to a human (or comment `/time retry` to send it back to the worker with the review attached). <!-- time {"beat":"needs-human","pr":110} -->
Author
Owner

/time retry

The objection is right and small: the adoption guard must also accept would-dispatch (a dry-run marker) and needs-done, since neither means a worker ran; add the dry-run→live test haiku asked for. The two non-blocking points are worth taking in the same round: say in the PR body that adoption trusts the reviewer gate (any open PR whose body closes the card, whoever opened it), and make the PR: #N line match only when it is the whole line.

/time retry The objection is right and small: the adoption guard must also accept `would-dispatch` (a dry-run marker) and `needs-done`, since neither means a worker ran; add the dry-run→live test haiku asked for. The two non-blocking points are worth taking in the same round: say in the PR body that adoption trusts the reviewer gate (any open PR whose body closes the card, whoever opened it), and make the `PR: #N` line match only when it is the whole line.

⏱️ Time: Claude Sonnet (Anthropic) is answering the review on PR #110 now, on branch time/card-93.

⏱️ Time: Claude Sonnet (Anthropic) is answering the review on PR #110 now, on branch `time/card-93`. <!-- time {"beat":"dispatched","launched":true,"worker":"anthropic"} -->

⏱️ Time: sonnet pushed its answer to PR #110 (7 steps, claude-sonnet-5-5). Review and landing follow on the next beat.

⏱️ Time: `sonnet` pushed its answer to PR #110 (7 steps, claude-sonnet-5-5). Review and landing follow on the next beat. <!-- time {"beat":"dispatched","worker":"anthropic","revised":true,"pr":110,"steps":7,"seat":"sonnet","model":"claude-sonnet-5-5"} -->

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

⏱️ Time: PR #110 is up for this card. `haiku` reviewed it on the PR. <!-- time {"beat":"pr","pr":110,"launched":false,"review":"venice","seat":"haiku"} -->
time closed this issue 2026-10-18 04:39:50 +00:00

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

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

No dependencies set.

Reference: teahubxyz/time#93