You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Complete the automatic Issue closure repair after the preserved interrupted attempts #80 and #81 using the production once mode
Problem
Roc verifies the PR merge and records done, but leaves the GitHub Issue open. Generated PRs also omit the source Issue link. This requires manual cleanup and breaks GitHub-native task management.
Desired outcome
Each generated managed-task PR clearly references its source Issue. Once Roc has verified the intended merged head in the configured target and confirmed the durable done checkpoint, it closes that Issue with completed reason. Already done open Issues are reconciled on polling/restart. Closure failures remain observable and retryable without replaying roles, hooks, publication or merge. Preserve the existing trusted-approval/spec checks and GitHub authoritative state. This is a replacement execution for Issue #80, cancelled by a confirmed GitHub no-route-to-host read failure. Do not change #80 or its checkpoint. The prior Scout findings are below; inspect the relevant files efficiently and avoid rereading whole files repeatedly. {"kind":"scout","summary":"Add a plain Related issue: #N reference only for canonical issue-N task IDs. Reuse the existing verified-merge → confirmed done checkpoint boundary, then reconcile Issue closure separately. Poll done-but-open tasks through the same repair path, rechecking remote authority and exact execution/spec identity without replaying roles, hooks, publication or merge. Preserve done on closure failure and emit a sanitized, retryable diagnostic. Document new production functions with concise JSDoc.","files":["src/github/pr-publisher.ts: pullRequestBody — add the source Issue reference for managed IDs; preserve legacy generic IDs and existing publication reconciliation.","src/github/issue-reader.ts: GitHubRemoteIssueReader — add an explicit repository-scoped completed closure operation with safe write-error classification and remote-state reconciliation.","src/github/execution-store.ts: IssueAccess, GitHubExecutionStore.get/save/decode — gate closure on freshly confirmed, approved, unchanged done evidence; bind the expected Issue and execution hash, skip already-closed Issues, and never modify the done checkpoint on close failure.","src/scheduler/github-runner.ts: claimNext, reconcileMerge, readPr — invoke closure after successful done checkpoint confirmation and repair done-open tasks on polling; verify recorded PR number, owned branch, intended head, configured target, mergeCommit and fetched-target ancestry before repair.","test/helpers/github-native.ts: memoryGitHub — model closure state, completed reason, call ordering, denied writes and lost responses.","test/github/issue-reader.test.ts; test/github/execution-store.test.ts; test/github/pr-publisher.test.ts — extend existing boundary fixtures.","test/scheduler/github-runner.test.ts; test/integration/github-native-execution.test.ts — add focused recovery cases and one vertical createFakeHarness flow."],"tests":["test/github/pr-publisher.test.ts: verify create/edit bodies reference the exact issue-N source with no closing keywords; existing T1 fixtures must produce no fabricated reference.","test/github/issue-reader.test.ts: verify explicit completed closure arguments and sanitized write failures.","test/github/execution-store.test.ts: extend lost-response and withdrawn-approval cases to cover already-closed idempotence, uncertain closure readback, and stale or wrong-Issue execution rejection.","test/scheduler/github-runner.test.ts: cover missing/mismatched PR and merge evidence, changed target/specification, withdrawn approval, and done-label-only tasks; closure repair must leave execution unchanged.","test/integration/github-native-execution.test.ts: add one Fake Harness flow through publication, verified merge into a non-default target, confirmed done readback and closure; simulate denied closure and restart, asserting no role/hook/publication/merge replay.","bun run test test/github test/scheduler test/integration/github-native-execution.test.ts test/integration/automatic-merge.test.ts","bun run check"],"risks":["Making IssueAccess closure mandatory also affects test/helpers/github-plan.ts: memoryPlan constructs a store with no closure method, and test/integration/automatic-merge.test.ts uses that API. github-plan.ts is outside the explicitly named helper scope; resolve this scope/API constraint before implementation.","GitHubExecutionStore.list validates complete plans, but get only decodes one Issue. Fresh closure reads must not discard a list-level blockedReason or accept a different execution/specification; existing save readback confirms execution content but does not itself enforce current approval for an existing checkpoint.","ExecutionRecordSchema permits done records without publication.number or mergeCommit. claimNext currently skips done tasks, so adding repair must explicitly require and verify evidence rather than trusting phase or roc:done labels.","coordinate can propagate errors when interrupt refuses to rewrite done. Closure failures therefore need their own nonfatal reporting boundary; otherwise a successfully completed task could stop polling instead of retrying closure. Keep GITHUB_CHECKPOINT_UNCONFIRMED fatal and never close before save confirms done."]} The prior uncommitted partial implementation is at /private/tmp/roc-close-proof-3j9VYo/repo.agile-worktrees/issue-80. Read its git diff as optional context; it is incomplete and untested, so finish and validate the design in your own worktree. Do not modify that prior worktree. This is a replacement execution for Issue #81, cancelled during background polling without a captured failed GitHub command. Do not change #80 or #81 or its checkpoint. The prior Scout findings are below; inspect the relevant files efficiently and avoid rereading whole files repeatedly. {"kind":"scout","summary":"Add a plain source-Issue reference for canonical issue-N PRs and a separate idempotent closure repair path after verified merge and confirmed done readback. Reuse that path for done-open polling; freshly validate plan, approval, specification and exact execution identity before closing as completed. Keep closure failures nonfatal, observable and retryable without checkpoint mutation or execution replay. Add concise JSDoc to new production functions; leave Issue #80 and its worktree untouched.","files":["src/github/pr-publisher.ts: pullRequestBody — add Related issue: #N only for canonical issue-N IDs; preserve generic IDs and create/edit reconciliation.","src/github/issue-reader.ts: GitHubRemoteIssueReader, mustRun — add repository-scoped completed closure, already-closed no-op, uncertain-response readback and sanitized write classification.","src/github/execution-store.ts: IssueAccess, GitHubExecutionStore.list/get/save — add closure authorization bound to the expected Issue, envelope and exact confirmed done execution; preserve plan-level blocking and never rewrite done on closure failure.","src/scheduler/github-runner.ts: claimNext, reconcileMerge, readPr — repair done-open tasks without coordinate execution; verify recorded PR, owned branch, intended head, configured target, mergeCommit and fetched-target ancestry before closure.","test/helpers/github-native.ts: memoryGitHub; test/helpers/github-plan.ts: memoryPlan — extend closure doubles with state, reason, ordering and failure controls; both are now in scope.","test/github/pr-publisher.test.ts; test/github/issue-reader.test.ts; test/github/execution-store.test.ts; test/scheduler/github-runner.test.ts — extend existing boundary fixtures.","test/integration/github-native-execution.test.ts — add one createFakeHarness vertical closure/restart flow alongside existing RecordedPiClient coverage."],"tests":["test/github/pr-publisher.test.ts: assert create/edit bodies reference the exact managed Issue without closing keywords; T1 and malformed managed IDs receive no fabricated reference.","test/github/issue-reader.test.ts; test/github/execution-store.test.ts: cover explicit completed arguments, sanitized failures, confirmed done-before-close ordering, lost responses, already-closed reason preservation, withdrawn approval and stale/wrong-Issue execution.","test/scheduler/github-runner.test.ts: cover done-label-only and missing/mismatched PR, head, branch, target, mergeCommit, ancestry, specification and approval evidence; assert repair leaves checkpoints unchanged.","test/integration/github-native-execution.test.ts: use createFakeHarness through publication and verified merge into a non-default target; deny closure, restart and retry with no role, hook, publication or merge replay.","bun run test test/github test/scheduler test/integration/github-native-execution.test.ts test/integration/automatic-merge.test.ts","bun run check"],"risks":["GitHubExecutionStore.list validates complete plans, while get only decodes one Issue; save readback confirms execution content but does not enforce current approval for existing checkpoints. Closure must retain list-level blocking and freshly compare authority and execution identity.","ExecutionRecordSchema permits done without publication.number or mergeCommit, and claimNext currently skips done. Neither phase nor roc:done labels supply sufficient closure evidence.","coordinate propagates errors when interrupt refuses to rewrite done. Closure needs its own nonfatal diagnostic boundary; GITHUB_CHECKPOINT_UNCONFIRMED must remain fatal and prevent closure.","The Issue #80 diff contains only partial publisher/reader/store changes, with no runner wiring or tests. Its optional closure API is unnecessary if both in-scope helpers are updated; existing automatic-merge and backend-session fixtures inherit those helper APIs."]} The prior uncommitted partial implementation is at /private/tmp/roc-close-proof-3j9VYo/repo.agile-worktrees/issue-81. Read its git diff as optional context; it is incomplete and untested, so finish and validate the design in your own worktree. Do not modify that prior worktree.
Scope
src/github/issue-reader.ts
src/github/execution-store.ts
src/github/pr-publisher.ts
src/scheduler/github-runner.ts
test/github
test/scheduler
test/helpers
test/integration/github-native-execution.test.ts
Non-goals
No SQLite, new queue, schema migration or general workflow abstraction. Do not change model routing, merge guards, target branches, workflows, dependencies, README files, or unrelated bugs such as Issue Investigate unexplained cancellation before base refresh #79.
Do not close unmerged, rejected, retired, awaiting_merge, blocked/unapproved or changed-spec Issues. Never infer completion from a status label alone. Never overwrite a human-closed Issue reason or reopen a closed Issue.
Only edit files in scope; allow small updates to test doubles in listed test directories if API shape changes. Do not commit or push manually; Roc handles publication.
Use a plain Related issue / Refs link, rather than Closes/Fixes keywords, so GitHub cannot auto-close before Roc persists verified done. For legacy generic task IDs, never manufacture an Issue number.
Acceptance criteria
A real issue-N task PR body links the exact source Issue; legacy non-Issue IDs have no fabricated link.
An open, approved, unchanged managed Issue closes as completed only after a confirmed done checkpoint with publication number and verified mergeCommit evidence. This works for configured non-default target branches and manual or auto merged PRs.
Polling/restart discovers done-but-open Issues and retries closure with a fresh authority read; the repair cannot accidentally act on another task or altered execution/specification. No model/hook/merge replay occurs.
Already closed Issues are no-ops. An uncertain close response is reconciled by reading the remote state. A failed close leaves done intact and emits a safe actionable diagnostic so a later poll can retry.
Use one vertical Fake Harness integration test plus focused boundary cases for done-write-before-close ordering, restart retry, lost response/already-closed idempotence, and absence/mismatch of merge evidence or approval. Keep tests small and meaningful.
All existing tests, typecheck, lint pass. Add concise JSDoc to all new named production functions.
close-issue-after-merge-once — Fix: finish Issue closure after merge, single-run recovery for #81
Plan: sha256:66d954c6b13203720d428baad66fafb39c299cc2cf35740cde21f7da2b891f0f
Cycle: 2026-W37
Priority: 0
Risk: medium
Token ceiling: 500000
Goal
Complete the automatic Issue closure repair after the preserved interrupted attempts #80 and #81 using the production once mode
Problem
Roc verifies the PR merge and records done, but leaves the GitHub Issue open. Generated PRs also omit the source Issue link. This requires manual cleanup and breaks GitHub-native task management.
Desired outcome
Each generated managed-task PR clearly references its source Issue. Once Roc has verified the intended merged head in the configured target and confirmed the durable done checkpoint, it closes that Issue with completed reason. Already done open Issues are reconciled on polling/restart. Closure failures remain observable and retryable without replaying roles, hooks, publication or merge. Preserve the existing trusted-approval/spec checks and GitHub authoritative state. This is a replacement execution for Issue #80, cancelled by a confirmed GitHub no-route-to-host read failure. Do not change #80 or its checkpoint. The prior Scout findings are below; inspect the relevant files efficiently and avoid rereading whole files repeatedly. {"kind":"scout","summary":"Add a plain Related issue: #N reference only for canonical issue-N task IDs. Reuse the existing verified-merge → confirmed done checkpoint boundary, then reconcile Issue closure separately. Poll done-but-open tasks through the same repair path, rechecking remote authority and exact execution/spec identity without replaying roles, hooks, publication or merge. Preserve done on closure failure and emit a sanitized, retryable diagnostic. Document new production functions with concise JSDoc.","files":["src/github/pr-publisher.ts: pullRequestBody — add the source Issue reference for managed IDs; preserve legacy generic IDs and existing publication reconciliation.","src/github/issue-reader.ts: GitHubRemoteIssueReader — add an explicit repository-scoped completed closure operation with safe write-error classification and remote-state reconciliation.","src/github/execution-store.ts: IssueAccess, GitHubExecutionStore.get/save/decode — gate closure on freshly confirmed, approved, unchanged done evidence; bind the expected Issue and execution hash, skip already-closed Issues, and never modify the done checkpoint on close failure.","src/scheduler/github-runner.ts: claimNext, reconcileMerge, readPr — invoke closure after successful done checkpoint confirmation and repair done-open tasks on polling; verify recorded PR number, owned branch, intended head, configured target, mergeCommit and fetched-target ancestry before repair.","test/helpers/github-native.ts: memoryGitHub — model closure state, completed reason, call ordering, denied writes and lost responses.","test/github/issue-reader.test.ts; test/github/execution-store.test.ts; test/github/pr-publisher.test.ts — extend existing boundary fixtures.","test/scheduler/github-runner.test.ts; test/integration/github-native-execution.test.ts — add focused recovery cases and one vertical createFakeHarness flow."],"tests":["test/github/pr-publisher.test.ts: verify create/edit bodies reference the exact issue-N source with no closing keywords; existing T1 fixtures must produce no fabricated reference.","test/github/issue-reader.test.ts: verify explicit completed closure arguments and sanitized write failures.","test/github/execution-store.test.ts: extend lost-response and withdrawn-approval cases to cover already-closed idempotence, uncertain closure readback, and stale or wrong-Issue execution rejection.","test/scheduler/github-runner.test.ts: cover missing/mismatched PR and merge evidence, changed target/specification, withdrawn approval, and done-label-only tasks; closure repair must leave execution unchanged.","test/integration/github-native-execution.test.ts: add one Fake Harness flow through publication, verified merge into a non-default target, confirmed done readback and closure; simulate denied closure and restart, asserting no role/hook/publication/merge replay.","bun run test test/github test/scheduler test/integration/github-native-execution.test.ts test/integration/automatic-merge.test.ts","bun run check"],"risks":["Making IssueAccess closure mandatory also affects test/helpers/github-plan.ts: memoryPlan constructs a store with no closure method, and test/integration/automatic-merge.test.ts uses that API. github-plan.ts is outside the explicitly named helper scope; resolve this scope/API constraint before implementation.","GitHubExecutionStore.list validates complete plans, but get only decodes one Issue. Fresh closure reads must not discard a list-level blockedReason or accept a different execution/specification; existing save readback confirms execution content but does not itself enforce current approval for an existing checkpoint.","ExecutionRecordSchema permits done records without publication.number or mergeCommit. claimNext currently skips done tasks, so adding repair must explicitly require and verify evidence rather than trusting phase or roc:done labels.","coordinate can propagate errors when interrupt refuses to rewrite done. Closure failures therefore need their own nonfatal reporting boundary; otherwise a successfully completed task could stop polling instead of retrying closure. Keep GITHUB_CHECKPOINT_UNCONFIRMED fatal and never close before save confirms done."]} The prior uncommitted partial implementation is at /private/tmp/roc-close-proof-3j9VYo/repo.agile-worktrees/issue-80. Read its git diff as optional context; it is incomplete and untested, so finish and validate the design in your own worktree. Do not modify that prior worktree. This is a replacement execution for Issue #81, cancelled during background polling without a captured failed GitHub command. Do not change #80 or #81 or its checkpoint. The prior Scout findings are below; inspect the relevant files efficiently and avoid rereading whole files repeatedly. {"kind":"scout","summary":"Add a plain source-Issue reference for canonical issue-N PRs and a separate idempotent closure repair path after verified merge and confirmed done readback. Reuse that path for done-open polling; freshly validate plan, approval, specification and exact execution identity before closing as completed. Keep closure failures nonfatal, observable and retryable without checkpoint mutation or execution replay. Add concise JSDoc to new production functions; leave Issue #80 and its worktree untouched.","files":["src/github/pr-publisher.ts: pullRequestBody — add Related issue: #N only for canonical issue-N IDs; preserve generic IDs and create/edit reconciliation.","src/github/issue-reader.ts: GitHubRemoteIssueReader, mustRun — add repository-scoped completed closure, already-closed no-op, uncertain-response readback and sanitized write classification.","src/github/execution-store.ts: IssueAccess, GitHubExecutionStore.list/get/save — add closure authorization bound to the expected Issue, envelope and exact confirmed done execution; preserve plan-level blocking and never rewrite done on closure failure.","src/scheduler/github-runner.ts: claimNext, reconcileMerge, readPr — repair done-open tasks without coordinate execution; verify recorded PR, owned branch, intended head, configured target, mergeCommit and fetched-target ancestry before closure.","test/helpers/github-native.ts: memoryGitHub; test/helpers/github-plan.ts: memoryPlan — extend closure doubles with state, reason, ordering and failure controls; both are now in scope.","test/github/pr-publisher.test.ts; test/github/issue-reader.test.ts; test/github/execution-store.test.ts; test/scheduler/github-runner.test.ts — extend existing boundary fixtures.","test/integration/github-native-execution.test.ts — add one createFakeHarness vertical closure/restart flow alongside existing RecordedPiClient coverage."],"tests":["test/github/pr-publisher.test.ts: assert create/edit bodies reference the exact managed Issue without closing keywords; T1 and malformed managed IDs receive no fabricated reference.","test/github/issue-reader.test.ts; test/github/execution-store.test.ts: cover explicit completed arguments, sanitized failures, confirmed done-before-close ordering, lost responses, already-closed reason preservation, withdrawn approval and stale/wrong-Issue execution.","test/scheduler/github-runner.test.ts: cover done-label-only and missing/mismatched PR, head, branch, target, mergeCommit, ancestry, specification and approval evidence; assert repair leaves checkpoints unchanged.","test/integration/github-native-execution.test.ts: use createFakeHarness through publication and verified merge into a non-default target; deny closure, restart and retry with no role, hook, publication or merge replay.","bun run test test/github test/scheduler test/integration/github-native-execution.test.ts test/integration/automatic-merge.test.ts","bun run check"],"risks":["GitHubExecutionStore.list validates complete plans, while get only decodes one Issue; save readback confirms execution content but does not enforce current approval for existing checkpoints. Closure must retain list-level blocking and freshly compare authority and execution identity.","ExecutionRecordSchema permits done without publication.number or mergeCommit, and claimNext currently skips done. Neither phase nor roc:done labels supply sufficient closure evidence.","coordinate propagates errors when interrupt refuses to rewrite done. Closure needs its own nonfatal diagnostic boundary; GITHUB_CHECKPOINT_UNCONFIRMED must remain fatal and prevent closure.","The Issue #80 diff contains only partial publisher/reader/store changes, with no runner wiring or tests. Its optional closure API is unnecessary if both in-scope helpers are updated; existing automatic-merge and backend-session fixtures inherit those helper APIs."]} The prior uncommitted partial implementation is at /private/tmp/roc-close-proof-3j9VYo/repo.agile-worktrees/issue-81. Read its git diff as optional context; it is incomplete and untested, so finish and validate the design in your own worktree. Do not modify that prior worktree.
Scope
Non-goals
Acceptance criteria
Validation
Dependencies