feat(mcp): set_pbi_pr + mark_pbi_pr_merged tools voor PBI-PR-gating (#18)

* feat(ST-mhj9f2la): add set_pbi_pr MCP tool

- Add pr_url and pr_merged_at fields to Pbi model in schema
- Implement set_pbi_pr tool: writes pr_url, clears pr_merged_at (idempotent)
- AuthZ via requireWriteAccess + userCanAccessProduct through pbi.product_id
- 10 tests: happy path, not-found, no-access, demo-denied, schema validation
- Update README tools table and bump version to 0.2.0

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat(ST-mhj9f2la): add mark_pbi_pr_merged MCP tool

- Implement mark_pbi_pr_merged: sets pr_merged_at = now() on a PBI
- Requires pr_url to be set; returns error if not (geen gekoppelde PR)
- Idempotent: re-calling overwrites the timestamp
- AuthZ via requireWriteAccess + userCanAccessProduct through pbi.product_id
- 6 tests: happy path, no-pr_url, idempotent, no-access, not-found, demo-denied
- Update README tools table with mark_pbi_pr_merged entry

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* docs(ST-mhj9f2la): expand README with set_pbi_pr + mark_pbi_pr_merged docs

Add full signature/input/output/error documentation sections for both
new tools, following the verify_task_against_plan pattern.
Version already bumped to 0.2.0 in earlier commit.
Tag + MCP_GIT_REF pin in scrum4me-docker to be done by maintainer after merge.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Janpeter Visser 2026-05-03 16:25:53 +02:00 committed by GitHub
parent 2c85f4d239
commit 3ce2c044c4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 404 additions and 36 deletions

View file

@ -28,6 +28,8 @@ activity and create todos via native tool calls instead of curl.
| `wait_for_job` | Block until a QUEUED ClaudeJob is available, claim it atomically, return full task context with frozen `plan_snapshot`, `worktree_path`, and `branch_name` | no |
| `update_job_status` | Report job transition to `running`, `done`, or `failed`; triggers SSE event to UI; cleans up worktree on terminal transitions | no |
| `verify_task_against_plan` | Compare frozen `plan_snapshot` against current plan + story logs + commits; returns per-AC ✓/✗/? heuristic and drift-score | yes (read-only) |
| `set_pbi_pr` | Write `pr_url` on a PBI and clear `pr_merged_at`. Idempotent: re-calling overwrites `pr_url` and resets `pr_merged_at` to null | no |
| `mark_pbi_pr_merged` | Set `pr_merged_at = now()` on a PBI. Requires `pr_url` to already be set. Idempotent: re-calling overwrites the timestamp | no |
Demo accounts may read but writes return `PERMISSION_DENIED`.
@ -71,6 +73,61 @@ Compares the immutable snapshot captured at claim time against the current state
- Plan_snapshot is NULL voor jobs die zijn geclaimed vóór versie met snapshot-feature — rapport meldt "no baseline"
- Gebruik het rapport als startpunt, niet als definitief oordeel; PR-review blijft leidend
### set_pbi_pr
Links a GitHub Pull Request to a PBI and clears any previous merge timestamp. Safe to call multiple times — idempotent.
**Input**
```json
{ "pbi_id": "cmoprewcf000q...", "pr_url": "https://github.com/owner/repo/pull/42" }
```
`pr_url` must match `^https://github\.com/[^/]+/[^/]+/pull/\d+$`. Any other format is rejected with a schema error.
**Output**
```json
{ "ok": true, "pbi_id": "cmoprewcf000q...", "pr_url": "https://github.com/owner/repo/pull/42" }
```
**Errors**
| Condition | Message |
|---|---|
| PBI not found or inaccessible | `PBI <id> not found or not accessible` |
| Demo account | `PERMISSION_DENIED: Demo accounts cannot perform write operations` |
| Invalid URL format | `VALIDATION_ERROR: pr_url: Invalid` |
### mark_pbi_pr_merged
Records that the linked PR has been merged by setting `pr_merged_at = now()`. Requires `set_pbi_pr` to have been called first. Idempotent: re-calling overwrites the timestamp.
**Input**
```json
{ "pbi_id": "cmoprewcf000q..." }
```
**Output**
```json
{
"ok": true,
"pbi_id": "cmoprewcf000q...",
"pr_url": "https://github.com/owner/repo/pull/42",
"pr_merged_at": "2026-05-03T12:00:00.000Z"
}
```
**Errors**
| Condition | Message |
|---|---|
| PBI not found or inaccessible | `PBI <id> not found or not accessible` |
| `pr_url` not set | `PBI <id> heeft geen gekoppelde PR` |
| Demo account | `PERMISSION_DENIED: Demo accounts cannot perform write operations` |
## Prompts
- `implement_next_story` — full workflow: fetch context, log plan, walk