night shift: hand work back as pull requests, not local branches #30

Merged
art merged 2 commits from night-shift-pull-requests into main 2026-08-02 05:56:57 +00:00
Collaborator

Night-shift work landed on local night/issue-<n>-<slug> branches that were never pushed,
so reviewing a night meant git log across a handful of branches that existed only on the
box that made them. This makes each worked issue a pull request instead.

queue.py finish --branch is now the whole handoff: push the branch, open a PR whose
body is the worker's review note (with Closes #<n>, so a merge closes the issue), comment
the PR link on the issue, move the label. The note stops being duplicated — it lives with
the diff, and the issue points at it.

Pushing lives in queue.py, not in the subagent brief. It is the run's one
outward-facing action, so confining it to the handoff means a worker can publish its own
branch and nothing else, and .claude/settings.json covers it by allowlisting queue.py
rather than granting bare git push. Never forced: a branch that diverged because review
fixups were pushed onto it fails the handoff rather than discarding them. Nothing is merged
or approved by the run.

New queue.py release — the outcome last night was missing. The #16 worker was killed
by a session limit, which is not an obstacle; marking it blocked would have hidden a
workable issue from every future night. release just un-claims it.

Opening a PR needs the write:repository token scope, which art-bot's token did not have;
the 403 now names the missing scope instead of dumping the raw error, since it would
otherwise surface at 02:00 at the very last step of a night's work.

Verification

  • The git helpers and both finish paths exercised against the live repo; this PR and the
    five below were opened by the new code path.
  • settings.json re-validated as JSON; CLI help checked for finish and release.
  • No Go, style, config or database changes — nothing to build or reimport.

Note that the preflight requires the tree to be on main, so until this is merged a night
run still uses the old branch-only flow.

Night-shift work landed on local `night/issue-<n>-<slug>` branches that were never pushed, so reviewing a night meant `git log` across a handful of branches that existed only on the box that made them. This makes each worked issue a pull request instead. **`queue.py finish --branch` is now the whole handoff:** push the branch, open a PR whose body is the worker's review note (with `Closes #<n>`, so a merge closes the issue), comment the PR link on the issue, move the label. The note stops being duplicated — it lives with the diff, and the issue points at it. **Pushing lives in `queue.py`, not in the subagent brief.** It is the run's one outward-facing action, so confining it to the handoff means a worker can publish its own branch and nothing else, and `.claude/settings.json` covers it by allowlisting `queue.py` rather than granting bare `git push`. Never forced: a branch that diverged because review fixups were pushed onto it fails the handoff rather than discarding them. Nothing is merged or approved by the run. **New `queue.py release`** — the outcome last night was missing. The #16 worker was killed by a session limit, which is not an obstacle; marking it `blocked` would have hidden a workable issue from every future night. `release` just un-claims it. Opening a PR needs the `write:repository` token scope, which art-bot's token did not have; the 403 now names the missing scope instead of dumping the raw error, since it would otherwise surface at 02:00 at the very last step of a night's work. ### Verification - The git helpers and both `finish` paths exercised against the live repo; this PR and the five below were opened by the new code path. - `settings.json` re-validated as JSON; CLI help checked for `finish` and `release`. - No Go, style, config or database changes — nothing to build or reimport. Note that the preflight requires the tree to be on `main`, so until this is merged a night run still uses the old branch-only flow.
Reviewing a night's output meant `git log night/issue-<n>-*` across a handful of
branches that existed only on this box. That does not scale past about one issue,
and it is the wrong shape for the actual morning task, which is reading a diff and
asking for a tweak.

`queue.py finish --branch` is now the whole handoff: push the branch, open a PR
against main with the worker's review note as its body and `Closes #<n>` so a merge
closes the issue, comment the PR link on the issue, move the label. The note stops
being duplicated — it lives in the PR, where the diff is, and the issue gets a
pointer.

Pushing lives here rather than in the subagent brief on purpose. It is the run's one
outward-facing action, so confining it to the handoff means a worker cannot push
anything else, and .claude/settings.json can allowlist it by allowlisting queue.py
instead of granting bare `git push`. The push is never forced: a branch that diverged
because review fixups were pushed onto it fails the handoff rather than discarding
them. Nothing is ever merged or approved by the run.

Also adds `queue.py release`, the outcome last night was missing. A worker killed by
a session limit has hit no obstacle, and marking its issue `blocked` would hide a
perfectly workable issue from every future night; release just un-claims it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The token opens issues fine, so this only fails at the last step of a night's
work, hours after anyone could react. Name the scope and the fix.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
art merged commit 0cb0c3afcc into main 2026-08-02 05:56:57 +00:00
art deleted branch night-shift-pull-requests 2026-08-02 05:56:57 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
art/ismap!30
No description provided.