Skip to content

fix(sync): keep a human reviewer when parking an issue in maintainer wait - #210

Merged
alvarosanchez merged 2 commits into
mainfrom
fix/preserve-human-reviewer-on-maintainer-wait
Sep 17, 2026
Merged

alvarosanchez merged 2 commits into
mainfrom
fix/preserve-human-reviewer-on-maintainer-wait

Conversation

@alvarosanchez

Copy link
Copy Markdown
Owner

Why

updatePaperclipIssueState treats clearAssignee as "unassign everything": it patches both assigneeAgentId and assigneeUserId to null. But that flag is only ever set from one place — shouldClearTransitionAssignee, which is nextStatus === 'in_review' && (nextTransitionAssignee === null || shouldPreserveMaintainerWaitRouting), i.e. parking an issue in maintainer wait.

In that situation the intent is "no agent owns this any more". A person deliberately assigned to the issue is the reviewer the work is waiting on, and today sync wipes them on the next pass — and, because the wiped state no longer matches the patch, re-wipes on every pass after that.

This blocks using assigneeUserId as the human-reviewer signal for PRs that are green and waiting on maintainers.

What

  • clearAssignee now clears the agent assignee and carries the issue's existing human assignee through in the same patch.
  • The preserved value is written into issuePatch explicitly rather than omitting the key, so isPaperclipIssuePatchApplied still recognises the settled state and a parked issue is not re-patched (and re-ledgered) on every sync pass — the regression class fix(sync): repeated no-op status decisions reuse their settled attempt #209 fixed.
  • SPEC.md / README.md updated: "leave unassigned" now reads "clear the agent assignee, keep a human assignee".

Tests

Two new cases in tests/issue-interactions-integration.spec.ts:

  • parking with a human assignee keeps assigneeUserId, drops assigneeAgentId, issues exactly one issues.update, and a second identical pass performs no further update and appends no extra ledger pair;
  • parking with only an agent assignee still unassigns the issue completely.

npm test 361/361 green, npm run typecheck clean.

🤖 Generated with Claude Code

…wait

`updatePaperclipIssueState` treated `clearAssignee` as "unassign everything"
and patched both `assigneeAgentId` and `assigneeUserId` to null. That flag is
only ever set for an `in_review` maintainer-wait park, where the intent is
"no agent owns this any more" — so a person deliberately parked on the issue
as the reviewer the work is waiting on was wiped on the next sync pass, and
re-wiped on every pass after that.

Clear the agent assignee and carry the issue's existing human assignee through
the same patch. Patching it explicitly (rather than omitting the key) keeps
`isPaperclipIssuePatchApplied` able to recognise the settled state, so a
parked issue is not re-patched and re-ledgered on every sync.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Copilot AI lite review requested due to automatic review settings September 17, 2026 14:00

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The current preservation logic and the new test setup can diverge from the worker’s real syncContext derivation when an agent assignee is present, risking continued clearing of assigneeUserId in the production path.

Get a fresh assessment by requesting another Copilot review.

Pull request overview

This PR adjusts GitHub Sync’s updatePaperclipIssueState behavior so “parking” an issue in in_review (maintainer wait) clears only the agent assignee while preserving any existing human assignee, preventing repeated re-patching and ledger churn on subsequent sync passes. It also updates the written spec/docs and adds integration coverage for the parking scenarios.

Changes:

  • Update updatePaperclipIssueState to avoid wiping a human assignee when clearAssignee is used for maintainer-wait parking.
  • Add integration tests to ensure parking is idempotent (no repeated issues.update and no repeated update_issue ledger pairs).
  • Update SPEC.md and README.md to reflect the “clear agent, keep human” semantics for maintainer wait.
File summaries
File Description
src/worker.ts Changes clearAssignee patching logic to preserve a human assignee when parking in maintainer wait.
tests/issue-interactions-integration.spec.ts Adds integration tests for maintainer-wait parking idempotency and assignee preservation.
SPEC.md Updates normative behavior for maintainer-wait unassignment to preserve human assignee while clearing agent.
README.md Updates documentation to match the new maintainer-wait assignee semantics.
Review details
  • Files reviewed: 4/4 changed files
  • Comments generated: 2
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread src/worker.ts Outdated
Comment thread tests/issue-interactions-integration.spec.ts
`getPaperclipIssueSyncContext` answers "who owns this issue", and that resolves
to the agent whenever both ids are set — so reading the preserved human from the
principal would still null `assigneeUserId` in exactly the case the change is
meant to protect. Read the raw field off the live issue instead, falling back to
the sync context only when the live read came back empty.

The regression test seeded both ids but declared a user principal, so it passed
against the principal-based read. It now declares the agent principal the worker
would really derive, and fails without this fix.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@alvarosanchez
alvarosanchez merged commit 89e6d6f into main Sep 17, 2026
1 check passed
@alvarosanchez
alvarosanchez deleted the fix/preserve-human-reviewer-on-maintainer-wait branch September 17, 2026 14:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants