Single iteration of PR tending. Reads PR state, classifies new events, routes fixes, reports status. Called by /loop via /tend-pr setup. Can be invoked manually to run a single tick.
Execute one iteration of PR tending: read current state, classify new events, route fixes, update PR, report status. Designed to be called repeatedly by /loop.
$ARGUMENTS = <pr-number> <mode> [<manifest-path> <log-path>]
<pr-number>: Required. The PR to tend.<mode>: manifest or babysit.<manifest-path> and <log-path>: Required when mode is manifest. Path to the manifest and execution log.If arguments missing or malformed: error and halt with usage message.
Use a lock file at /tmp/tend-pr-lock-{pr-number}. Skip this iteration if the lock exists and isn't stale (significantly older than the expected polling interval). Remove stale locks. Create the lock at iteration start, remove at end.
Read the PR's current state: open/closed/merged/draft, new comments since last check, CI status, review status, unresolved threads.
Terminal states (handle per Output Protocol — end the loop):
Nothing new → Remove lock. Schedule next iteration.
First tick (tend-pr-log has no prior iterations): Everything is unprocessed — skip the "nothing new" shortcut and run the full classification pipeline.
Label source first (bot vs human — read ../tend-pr/references/known-bots.md), then classify intent (read ../tend-pr/references/classification-examples.md):
Compare against base branch first:
Manifest mode: Route actionable items to affected deliverables. Identify which deliverable(s) the comment or CI failure targets (include all potentially affected when ambiguous). Amend manifest via /define --amend <manifest-path> --from-do, then invoke /do <manifest-path> <log-path> --scope <affected-deliverable-ids>. If /do escalates, log the blocker, report the escalation to the user, and end the loop. Push changes and reply to the comment.
Babysit mode: Fix directly, push, reply.
False positives: Reply with explanation.
Uncertain: Reply asking for clarification, leave thread open.
Thread resolution rule: Resolve all bot threads after addressing (fix, reply, or both). Never resolve human threads — the reviewer owns their thread and will resolve it themselves.
Update the PR branch by merging the base branch in. Prefer merge over rebase to preserve review comment history (see Gotchas). Flag ambiguous conflicts to the user.
After changes, rewrite "what changed" sections to reflect the current diff. Preserve manual context (issue references, motivation, deployment notes). Update title if scope changed significantly.
Append to /tmp/tend-pr-log-{pr-number}.md: timestamp, actions taken, skipped items, remaining blockers, current PR state.
When the PR's merge state indicates it is mergeable (all required checks pass, required approvals obtained, no unresolved threads, no pending /do runs) — this is a terminal state. Ask the user about merging and end the loop per the Output Protocol.
Unresolved uncertain threads block merge-readiness — they represent unanswered questions that could surface actionable issues.
Determine merge requirements from the platform's merge state (e.g., GitHub branch protection rules), not hardcoded assumptions about what's required.
Stale thread escalation: If an uncertain comment has received no reply for several consecutive iterations, or an actionable comment was fixed (pushed + replied) but the thread remains unresolved for several consecutive iterations, escalate to the user: "Thread from @reviewer unresolved for [duration]: [uncertain — no reply / fixed — awaiting reviewer resolution]. Continue waiting, resolve, or ping reviewer?"
Every iteration MUST end with exactly one of these outcomes. The tick owns the full lifecycle — when a terminal state is reached, handle it completely (user interaction + loop termination) before returning.
When any STOP condition is reached: handle the user interaction described below, then end the loop — do not call ScheduleWakeup or CronCreate for the next iteration.