finish-issue-closure — Fix: preserve done-label recovery and document Issue closure
Plan: sha256:70ea3041106be1ce9d20740f1d192fc89f22262dc7f8db90365005f15f47ebd2
Cycle: 2026-W37
Priority: 0
Risk: low
Token ceiling: 250000
Goal
Preserve status-label recovery and task admission during automatic Issue closure, and document the behavior
Problem
PR #83 added the done branch before claimNext admission and syncLabels. This prevents failed done-label writes from being repaired on later polls, and bypasses the caller admission predicate for closure. The detailed READMEs also lack the closure behavior.
Desired outcome
In GitHubTaskRunner.claimNext, restore the existing admission check and status-label synchronization before the done-task closure branch. An admitted done task repairs labels then optionally closes its still-open Issue. A candidate rejected by admit must trigger neither label nor closure writes. Keep closure checks and all other behavior unchanged. Add focused regression coverage that a stale done label is repaired even when the Issue is already closed, and that admit=false prevents both repairs. Update the English and Traditional Chinese detailed READMEs to describe the implemented behavior accurately: plain Issue link on PR, verified merge into configured branch, confirmed done checkpoint, completed Issue closure, automatic retry on poll/restart without rerunning models. Mention that non-default targets work too. Read the current closure implementation first and match it exactly.
Scope
- src/scheduler/github-runner.ts
- test/scheduler/github-runner.test.ts
- README.details.md
- README.details.zh-HK.md
Non-goals
- Only edit the four scoped files. Keep the production fix to restoring admission and label synchronization ordering. Do not change other runtime behavior, workflow, dependencies, or unrelated documentation. Do not claim live proof or performance numbers. Do not commit or push manually.
Acceptance criteria
- An admitted done Issue with a stale lifecycle label has the label repaired on polling even if the Issue is already CLOSED, without starting any model or changing its execution record.
- An admit=false candidate causes no label synchronization, PR/merge checks, or Issue closure. Existing Issue closure safety checks remain intact.
- Both README details explain when closure happens and how failed closure recovers, consistently with src/github/execution-store.ts and src/scheduler/github-runner.ts.
- Preserve existing milestone scope and model effort settings; keep prose concise and natural. Avoid Closes/Fixes keyword examples that imply GitHub handles Roc's closing order.
Validation
- bun run check
- git diff --check
Dependencies
finish-issue-closure — Fix: preserve done-label recovery and document Issue closure
Plan: sha256:70ea3041106be1ce9d20740f1d192fc89f22262dc7f8db90365005f15f47ebd2
Cycle: 2026-W37
Priority: 0
Risk: low
Token ceiling: 250000
Goal
Preserve status-label recovery and task admission during automatic Issue closure, and document the behavior
Problem
PR #83 added the done branch before claimNext admission and syncLabels. This prevents failed done-label writes from being repaired on later polls, and bypasses the caller admission predicate for closure. The detailed READMEs also lack the closure behavior.
Desired outcome
In GitHubTaskRunner.claimNext, restore the existing admission check and status-label synchronization before the done-task closure branch. An admitted done task repairs labels then optionally closes its still-open Issue. A candidate rejected by admit must trigger neither label nor closure writes. Keep closure checks and all other behavior unchanged. Add focused regression coverage that a stale done label is repaired even when the Issue is already closed, and that admit=false prevents both repairs. Update the English and Traditional Chinese detailed READMEs to describe the implemented behavior accurately: plain Issue link on PR, verified merge into configured branch, confirmed done checkpoint, completed Issue closure, automatic retry on poll/restart without rerunning models. Mention that non-default targets work too. Read the current closure implementation first and match it exactly.
Scope
Non-goals
Acceptance criteria
Validation
Dependencies