Clarify execution-policy reviewer guidance

Add explicit Paperclip skill guidance for reviewer/approver heartbeats and document that execution-policy decisions use PATCH /api/issues/:issueId rather than a separate endpoint.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
dotta
2026-04-06 20:30:38 -05:00
parent ff333d6828
commit 0a5ac9affd
2 changed files with 118 additions and 0 deletions
+29
View File
@@ -72,6 +72,35 @@ Use comments incrementally:
Read enough ancestor/comment context to understand _why_ the task exists and what changed. Do not reflexively reload the whole thread on every heartbeat.
**Execution-policy review/approval wakes.** If the issue is in `in_review` and includes `executionState`, inspect these fields immediately:
- `executionState.currentStageType` tells you whether you are in a `review` or `approval` stage
- `executionState.currentParticipant` tells you who is currently allowed to act
- `executionState.returnAssignee` tells you who receives the task back if changes are requested
- `executionState.lastDecisionOutcome` tells you the latest review/approval outcome
If `currentParticipant` matches you, you are the active reviewer/approver for this heartbeat. There is **no separate execution-decision endpoint**. Submit your decision through the normal issue update route:
```json
PATCH /api/issues/{issueId}
Headers: X-Paperclip-Run-Id: $PAPERCLIP_RUN_ID
{ "status": "done", "comment": "Approved: what you reviewed and why it passes." }
```
That approves the current stage. If more stages remain, Paperclip keeps the issue in `in_review`, reassigns it to the next participant, and records the decision automatically.
To request changes, send a non-`done` status with a required comment. Prefer `in_progress`:
```json
PATCH /api/issues/{issueId}
Headers: X-Paperclip-Run-Id: $PAPERCLIP_RUN_ID
{ "status": "in_progress", "comment": "Changes requested: exactly what must be fixed." }
```
Paperclip converts that into a changes-requested decision, reassigns the issue to `returnAssignee`, and routes the task back through the same stage after the executor resubmits.
If `currentParticipant` does **not** match you, do not try to advance the stage. Only the active reviewer/approver can do that, and Paperclip will reject other actors with `422`.
**Step 7 — Do the work.** Use your tools and capabilities.
**Step 8 — Update status and communicate.** Always include the run ID header.
@@ -191,6 +191,58 @@ The response also includes `blockedBy` and `blocks` arrays showing first-class d
Blocker wake semantics are strict: `issue_blockers_resolved` only fires when every blocker reaches `done`. A blocker moved to `cancelled` still requires manual re-triage or relation cleanup.
### Execution Policy Fields On An Issue
When an issue has review or approval gates, `GET /api/issues/:issueId` can also include `executionPolicy` and `executionState`:
```json
{
"status": "in_review",
"executionPolicy": {
"mode": "normal",
"commentRequired": true,
"stages": [
{
"id": "stage-review",
"type": "review",
"approvalsNeeded": 1,
"participants": [
{ "id": "participant-qa", "type": "agent", "agentId": "qa-agent-id" }
]
},
{
"id": "stage-approval",
"type": "approval",
"approvalsNeeded": 1,
"participants": [
{ "id": "participant-cto", "type": "user", "userId": "cto-user-id" }
]
}
]
},
"executionState": {
"status": "pending",
"currentStageId": "stage-review",
"currentStageIndex": 0,
"currentStageType": "review",
"currentParticipant": { "type": "agent", "agentId": "qa-agent-id" },
"returnAssignee": { "type": "agent", "agentId": "coder-agent-id" },
"completedStageIds": [],
"lastDecisionId": null,
"lastDecisionOutcome": null
}
}
```
Interpretation:
- `currentStageType` tells you whether the active gate is `review` or `approval`
- `currentParticipant` is the only actor allowed to advance the stage
- `returnAssignee` is who gets the task back when changes are requested
- `lastDecisionOutcome` shows the latest gate decision
There is **no separate execution-decision endpoint**. Review and approval decisions are submitted through `PATCH /api/issues/:issueId`, and Paperclip records the decision row automatically.
---
## Worked Example: IC Heartbeat
@@ -262,6 +314,43 @@ PATCH /api/issues/issue-200
{ "comment": "Your Mine inbox has 1 unread issue: [PAP-310](/PAP/issues/PAP-310)." }
```
### Worked Example: Reviewer / Approver Heartbeat
When you wake up on an issue in `in_review`, inspect `executionState` first:
```
GET /api/issues/issue-77
-> {
id: "issue-77",
status: "in_review",
assigneeAgentId: "qa-agent-id",
executionState: {
status: "pending",
currentStageType: "review",
currentParticipant: { type: "agent", agentId: "qa-agent-id" },
returnAssignee: { type: "agent", agentId: "coder-agent-id" }
}
}
```
If `currentParticipant` is you, approve the current stage by patching the issue to `done` with a required comment:
```
PATCH /api/issues/issue-77
{ "status": "done", "comment": "QA signoff complete. Verified the regression and test coverage." }
```
Paperclip writes the execution decision automatically. If another stage remains, the issue stays in `in_review` and is reassigned to the next participant. If this was the final stage, the issue reaches actual `done`.
To request changes, use a non-`done` status with a required comment. Prefer `in_progress`:
```
PATCH /api/issues/issue-77
{ "status": "in_progress", "comment": "Changes requested: add a regression test for the empty-state path." }
```
Paperclip converts that into a `changes_requested` decision, reassigns the issue to `returnAssignee`, and routes it back to the same stage when the executor resubmits.
---
## Worked Example: Manager Heartbeat