Files
PaperClipAI/server
Devin Foley 0f12721ee9 fix(server): let board users cancel issues with an active review stage (#10655)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - The server enforces an issue execution policy. It gates status
changes while a review or approval stage is active.
> - A board user could not cancel a task while an agent reviewer held
the active stage. The API returned "Only the active reviewer or approver
can advance the current execution stage".
> - Board users own the board. They must always be able to edit and
cancel any task.
> - This pull request adds a board override to the execution stage
transition. A board cancel clears the pending stage state and proceeds
instead of raising an error.
> - The benefit is that board users can always stop work, even while a
review is pending or the stored stage state has drifted.

## Linked Issues or Issue Description

No public GitHub issue exists for this bug. Description follows
`bug_report.yml`:

**What happened?**

A board user set a task to `cancelled` while the task had an active
reviewer stage held by an agent. The PATCH failed with "Task Update
Failed... only the assigned approver or reviewer...". The same failure
occurred when the stored stage state had drifted: the server silently
forced the task back to `in_review` instead of honoring the cancel.

**Expected behavior**

A board user can always edit and cancel any task. A board cancel must
clear the pending review stage and apply the requested status.

**Steps to reproduce**

1. Create a task assigned to agent A with agent B configured as reviewer
in the execution policy.
2. Let agent A hand the task off so the review stage becomes active.
3. As the board user, set the task status to Cancelled.
4. The update fails with the reviewer-only error.

Related work: #5487 touches the execution-policy approver UI. It does
not address the board cancel path.

## What Changed

- `server/src/routes/issues.ts`: the issue PATCH route now passes
`allowBoardOverride` when the actor is a board user.
- `server/src/services/issue-execution-policy.ts`: when
`allowBoardOverride` is set and the requested status is not `in_review`
or `in_progress`, the transition clears `executionState` and proceeds.
This applies both while a stage decision is pending and when the stage
state has drifted, so a board cancel is no longer rejected or silently
flipped back to `in_review`.
- Reviewer gating is unchanged for everyone else: a board user who is
the active participant still uses the normal approve / request-changes
flow, and non-participant agents still receive the 422 guard.
- Assignee-only board updates on an `in_review` task keep the stage
state coherent: reassigning to an eligible stage participant re-pends
the stage with them as the current participant, while reassigning to a
non-participant (or unassigning) dissolves the review back to
`in_progress` instead of persisting an `in_review` issue with no
execution state or an ineligible participant.
- New unit tests and route tests cover board cancellation of an active
review stage and of a drifted pending review, plus reviewer swap,
non-participant reassignment, and unassignment during an active review.

## Verification

- In `server/`: `pnpm exec vitest run
src/__tests__/issue-execution-policy.test.ts
src/__tests__/issue-execution-policy-routes.test.ts` — 2 files, 73/73
tests pass on top of current `master`.
- In `server/`: `pnpm run typecheck` passes.

## Risks

- Low risk. The override branch runs only for board actors and only for
target statuses other than `in_review` and `in_progress`. Cancelling
clears `executionState`, so a later reopen starts from a fresh stage
state. Agent-facing flows and reviewer gating are unchanged.

## Model Used

- Claude Fable 5 (Anthropic), model ID `claude-fable-5`, running in
Claude Code (Claude Agent SDK) with extended thinking and agentic tool
use.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [ ] All Paperclip CI gates are green
- [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge
2026-08-01 15:43:13 -07:00
..