Skip to content

Commit 540e7b1

Browse files
neo-opus-adatobiuneo-gemini-3-1-pro
authored
feat(github-workflow): precondition + post-verify gate on manage_issue_assignees + lane-intent skill substrate (#11537) (#11541)
* feat(github-workflow): precondition + post-verify gate on manage_issue_assignees (#11537) Refactor IssueService.assignIssue to enforce a single guarded MCP operation contract per Discussion #11536 graduation: - Fetch current assignees via new GET_ISSUE_ASSIGNEES narrow query - requireUnassigned: true (default) rejects blind-add to occupied issues with ASSIGNEE_CONFLICT (HTTP 409); payload includes currentAssignees + attemptedAssignees for caller introspection - acknowledgedReassign: '<reason>' enables strict-replacement override (clear existing + add new). Reason persisted as audit-trail issue comment via raw ADD_COMMENT mutation (graph-readable provenance per GPT STEP_BACK AC8 carry-forward); graceful degradation on comment failure - Post-verify re-fetch confirms assignee state in response OpenAPI schema (ai/mcp/server/github-workflow/openapi.yaml): - Adds requireUnassigned + acknowledgedReassign parameters - Adds 409 ASSIGNEE_CONFLICT response - Documents 'single guarded MCP operation' semantics (NOT strict CAS) - Notes gh issue edit --add-assignee bypass ban (narrow scope per #11537) - Co-owner-add deferred to V2 per OQ3 resolution * feat(skills): add lane-intent skill substrate + peer-role-mode discipline expansion (#11537) New skill substrate at .agents/skills/lane-intent/ (Atlas-tier; conditionally loaded). Carries the full discipline that AGENTS.md §0 Inv 7 Map-tier entry-point (landing via #11534) does NOT need to: - SKILL.md: thin Map-tier router mirroring peer-role/SKILL.md frontmatter pattern with trigger-context + 'First payload line MUST declare' anchor - references/lane-intent-protocol.md: 7-section Atlas-tier discipline — Essential / 3-condition Scope-Trigger gate / Required A2A Shape / Non-Authoritative Semantics / 2h TTL + Recovery / Tool-Side Complement / Anti-Patterns / Cross-References. Canonical positive + negative examples for scope-trigger. - .claude/skills/lane-intent symlink (cross-harness) - skills.manifest.json entry alphabetical between industry-friction-radar and lead-role peer-role-mode.md §6.5 expanded: - [lane-claim] vs [lane-intent] semantic split (authoritative post-V-B-A vs non-authoritative pre-V-B-A) - AC2 timing rule: [lane-claim] only AFTER V-B-A + immediately before write - Tool-side enforcement note (manage_issue_assignees gate) - New §6.5.1: [lane-override] Protocol with 2h TTL + recovery semantics per AC10 (Gemini's OQ6 resolution) - §7 anti-pattern catalog: gh CLI assignee bypass + pre-V-B-A [lane-claim] ProgressiveDisclosureSkills.md: lane-intent entry in descriptive list + Skill Inventory table (Coordination type) * test(github-workflow): pin assignIssue ASSIGNEE_CONFLICT gate behavior (#11537) New test suite covers the precondition + post-verify gate's conflict path (the substrate-discipline value-add of #11537): - ASSIGNEE_CONFLICT returned when issue is already assigned + default requireUnassigned + no acknowledgedReassign - Multi-assignee currentAssignees in conflict payload (caller introspection) - Co-owner-add deferral OQ3 messaging surfaces in caller-facing prose - Precondition fetch invoked exactly once before conflict gate returns - Permission gate preserved: FORBIDDEN for READ-perm viewer, precondition fetch NOT called when permission denial fires first - Clear-mode preservation: empty assignees array does NOT trigger precondition fetch (gate-boundary pinned) 20/20 tests pass (15 existing + 5 new). Coverage gap documented for follow-up: override/strict-replacement/audit-trail paths depend on child_process.exec which has no ES-module-friendly mock pattern in the current test harness. Pin conflict-path only; integration tests would catch the execAsync-dependent flows. * chore(skills): compress lane-intent SKILL.md to 12-line routerByteBudget + add CodebaseOverview entry (#11537) CI lint feedback on PR #11541: - .agents/skills/lane-intent/SKILL.md was 15 lines; routerByteBudget cap is 12. Compressed by inlining the 3-bullet Source of Authority into a single line (preserves all 3 references) + tightening the read-protocol instruction wording. Frontmatter + content semantics unchanged. - learn/guides/fundamentals/CodebaseOverview.md was missing the lane-intent entry per the manifest's downstreamDocsTargets convention. Added a new 'Coordination' subsection (one-line lane-intent description) alongside existing Creative/Meta groupings. File-level catch-up of older missing skills (lead-role, peer-role, etc.) routes to separate ticket per scope-discipline. Both fixes are mechanical lint-driven corrections; no substantive scope change to the lane-intent primitive or the manage_issue_assignees gate. * chore(openapi): compress manage_issue_assignees description to usage contract (#11537) * chore(lane-intent): split skill into Atlas-essentials + ADR 0010 (#11537) Per operator substrate-discipline direction (2026-05-17 ~20:00Z): Map vs World Atlas is the critical discipline. Skill references stay operational-essentials only; edge cases + in-depth reasoning move to optional file or ADR. Substrate split: - .agents/skills/lane-intent/SKILL.md: unchanged Map-tier router (12 lines) - .agents/skills/lane-intent/references/lane-intent-protocol.md: TRIMMED from 8497 → 3574 bytes (-4923 bytes; 58% reduction). Atlas-tier essentials only: definition + 3-condition Scope-Trigger Gate + Required A2A Shape + TTL+Recovery + Tool-Side Complement + Anti-Patterns + Cross-Refs. Removed canonical positive/negative examples (moved to ADR), non-authoritative semantics deep rationale (compressed to 2-line callout in §0), substrate-evolution narrative (moved to ADR). - learn/agentos/decisions/0010-lane-intent-coordination-primitive.md (NEW): Deep reasoning + canonical positive/negative examples + edge cases (cross-family corrective-authorship vs lane-intent, co-owner-add OQ3 deferral, TTL-expired observability) + empirical anchors + sister primitives + future evolution candidates. Conditionally-loaded only when agent drills into architectural-decision substrate. Per-firing cumulative-future-sessions thought-budget impact: - BEFORE: 8497 bytes loaded EVERY `/lane-intent` skill-trigger firing - AFTER: 3574 bytes loaded every firing + 7145-byte ADR loaded rarely - NET: -4923 bytes per future firing (cumulative across all sessions × M firings = substantial thought-budget reduction) URL→#N normalization (6 GitHub stream-id URLs → short-form): - SKILL.md: Discussion #11536 link → short-form; +ADR 0010 ref - lane-intent-protocol.md (rewrite): zero HTTP URLs (all converted) - ADR 0010: zero HTTP URLs Honors ADR 0008 SKILL.md Anatomy and Authoring Contract: Map (SKILL.md always-loaded router) → Atlas (protocol.md operational essentials) → ADR (deep architectural-decision substrate). Future skill-substrate authoring discipline anchor for the cumulative-future-sessions thought-budget concern operator surfaced 2026-05-17 ~19:55Z. --------- Co-authored-by: tobiu <tobiasuhlig78@gmail.com> Co-authored-by: neo-gemini-3-1-pro <neo-gemini-3-1-pro@users.noreply.github.com>
1 parent e0de741 commit 540e7b1

12 files changed

Lines changed: 635 additions & 39 deletions

File tree

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
---
2+
name: lane-intent
3+
description: "Narrow, non-authoritative, TTL-bound pre-V-B-A signal for collision-prone / high-blast / long-V-B-A lanes (deep memory-mining, tech-debt-radar, multi-turn architectural V-B-A). Distinct from authoritative `[lane-claim]` (post-V-B-A). Triggers: Use this skill BEFORE broadcasting `[lane-intent] evaluating #N` to confirm scope-trigger qualifies — narrow scope, not blanket coverage. Do NOT auto-fire for short single-turn V-B-A where direct `[lane-claim]` after V-B-A suffices."
4+
---
5+
6+
# Lane-Intent Skill
7+
8+
Before broadcasting `[lane-intent] evaluating #N` OR explaining lane-intent semantics, read `.agents/skills/lane-intent/references/lane-intent-protocol.md` for the 3-condition scope-trigger gate, TTL+recovery semantics, and anti-patterns.
9+
10+
**Source of Authority:** AGENTS.md §0 Inv 7 (Map entry-point) + peer-role-mode §6.5 ([lane-claim] vs [lane-intent] split per #11537) + Discussion #11536 graduation + ADR 0010 (deep rationale).
11+
12+
**First payload line MUST declare:** "Lane-intent active: narrow non-authoritative pre-V-B-A signal, 2h TTL. Scope-trigger discipline applies — read protocol before broadcasting."
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
# Lane-Intent Protocol
2+
3+
*(Per #11537, graduated from Discussion #11536 OQ1. Deep rationale + canonical examples + edge cases → ADR 0010.)*
4+
5+
## 0. The Essential
6+
7+
**`[lane-intent]` is a narrow, non-authoritative, 2-hour TTL-bound A2A broadcast signaling peers you are EVALUATING a lane but have NOT yet completed V-B-A or written anything.**
8+
9+
```
10+
[lane-intent] evaluating #N ← non-authoritative, pre-V-B-A, narrow scope, 2h TTL
11+
[lane-claim] taking #N ← authoritative, post-V-B-A, immediately-before-write
12+
[lane-override] reclaiming #N ← corrective handoff, 2h TTL (peer-role-mode §6.5.1)
13+
```
14+
15+
**Non-authoritative semantics**: `[lane-intent]` does NOT count in peer-role-mode §6.6 Source-of-Authority hierarchy. A peer who proceeds past it is NOT violating substrate. Yield if a peer posts `[lane-claim]` faster.
16+
17+
## 1. Scope-Trigger Gate
18+
19+
`[lane-intent]` is **OPTIONAL** and **NARROW**. Broadcast ONLY when ALL three conditions hold:
20+
21+
1. **Collision-prone context** — visible duplicate-exploration risk (recently-touched substrate, high-blast topic, adjacent peer activity)
22+
2. **Long V-B-A required** — spans multiple turns OR heavy tooling (`/memory-mining`, `/tech-debt-radar`, deep `ask_knowledge_base`)
23+
3. **Real duplicate-work risk** — peer could plausibly start parallel exploration within the V-B-A window
24+
25+
Missing ANY → just complete V-B-A locally + `[lane-claim]` directly. Canonical positive/negative examples + edge cases: ADR 0010.
26+
27+
## 2. Required A2A Shape
28+
29+
```
30+
Subject: [lane-intent] evaluating #N
31+
OR
32+
[lane-intent] evaluating <substrate-description-with-stable-id>
33+
34+
Body:
35+
- WHAT: brief evaluation scope
36+
- WHY: which of the 3 scope-triggers fires
37+
- TIMELINE: rough V-B-A window
38+
- CONVERTS-TO: `[lane-claim] taking #N` or `[yield] <reason>`
39+
40+
Recipient: AGENT:*
41+
```
42+
43+
**Path-determinism**: unticketed substrate-descriptions need stable URL / discussion-number / explicit-substrate-ID (machine-queryable). Free-form forbidden.
44+
45+
## 3. TTL and Recovery
46+
47+
**TTL: 2 hours** (session lifespan). After 2h, `[lane-intent]` expires — consumers MUST ignore.
48+
49+
**Read-path semantics**: consumer-enforced. `list_messages` readers compute `sentAt + TTL` and treat expired as inert. Substrate does NOT auto-delete.
50+
51+
**Expiration paths**:
52+
- **Converted to `[lane-claim]`** — V-B-A done; claim supersedes
53+
- **Converted to `[yield]`** — V-B-A surfaced blocker/conflict/better path
54+
- **TTL-expired silently** — peer moved on; lane available
55+
56+
## 4. Tool-Side Complement
57+
58+
`[lane-intent]` is purely A2A. The mechanical assignee gate is `manage_issue_assignees` per #11537 (precondition + post-verify, fires post-V-B-A during `[lane-claim]`, NOT during `[lane-intent]` phase). Pre-V-B-A self-assign is forbidden.
59+
60+
## 5. Anti-Patterns
61+
62+
- **Blanket `[lane-intent]`** — over-triggering for every lane-pickup
63+
- **`[lane-intent]` as authority surrogate** — citing it in §6.6 conflict resolution
64+
- **`[lane-intent]` for short single-turn V-B-A** — over-triggering
65+
- **Open-ended intent** — no `CONVERTS-TO` declared → discipline-dressed-deference
66+
- **TTL ignored on read-path** — treating 8-hour-old intent as live state
67+
- **Self-assigning during `[lane-intent]` phase** — assignment is post-V-B-A only
68+
69+
## 6. Cross-References
70+
71+
- AGENTS.md §0 Invariant 7 — Map-tier entry-point (per #11534)
72+
- peer-role-mode §6.5 / §6.5.1 / §6.6 / §7 — `[lane-claim]` semantics + `[lane-override]` + authority hierarchy + anti-patterns
73+
- ADR 0010 — substrate-evolution rationale + canonical examples + edge cases + sister primitives

.agents/skills/peer-role/references/peer-role-mode.md

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,14 @@ Share vocabulary with `/lead-role`. A convergence artifact is either a linked Id
4949

5050
### 6.5 Lane-Announce-A2A Protocol
5151

52-
*(Codified per #11209, graduated from Discussion #11206 Option A-prime convergence.)*
52+
*(Codified per #11209, graduated from Discussion #11206 Option A-prime convergence. Expanded per #11537, graduated from Discussion #11536 Pre-Write Coordination Substrate.)*
5353

54-
Before any **write-operation** (state mutation, PR open, issue assignment, branch push creating new artifact), peer MUST send an A2A broadcast announcing the lane-claim. This is the collision-prevention substrate the Flat Peer-Team model needs to operate without orchestrator-worker delegation.
54+
The substrate operates **two distinct primitives** for pre-write coordination:
55+
56+
- **`[lane-claim]`** — authoritative, **post-V-B-A**, immediately-before-write-operation. Used for ticket-bound or substrate-bound lanes the peer is committing to execute. Counts in §6.6 Source-of-Authority hierarchy as "Current Public Authority" when paired with self-assign + open PR.
57+
- **`[lane-intent]`** — non-authoritative, **pre-V-B-A** soft signal, 2-hour TTL. NARROW SCOPE: only for collision-prone / high-blast / long-V-B-A lanes where duplicate exploration is plausible (e.g., deep `/memory-mining`, `/tech-debt-radar`, multi-turn architectural V-B-A). Does NOT count in §6.6 authority hierarchy. Per AGENTS.md §0 Invariant 7 entry-point + full discipline in `.agents/skills/lane-intent/` skill substrate.
58+
59+
**`[lane-claim]` AC2 timing rule (per #11537):** broadcast happens AFTER the source-of-authority collision check (§6.6) AND V-B-A scope-validation AND immediately before the write-operation. Pre-V-B-A `[lane-claim]` is forbidden — it dilutes authority semantics + creates race-to-announcement incentive (per Discussion #11536 GPT V-B-A rejection of Option B). If you need a pre-V-B-A signal because V-B-A will take multiple turns, use `[lane-intent]` (narrow scope only).
5560

5661
**Trigger scope — write-operations only**:
5762
- **REQUIRED**: file a ticket, open a PR, branch from `origin/dev`, assign an issue, push a commit that creates a new artifact
@@ -62,6 +67,25 @@ Before any **write-operation** (state mutation, PR open, issue assignment, branc
6267
- Body: scope-boundary statement (which files / surfaces / write-operations), expected timeline, source-of-authority collision-check findings (see §6.6)
6368
- Recipient: `AGENT:*` broadcast (let all peers V-B-A against parallel-claim risk)
6469

70+
**Tool-side enforcement (per #11537 AC3/AC4):** issue assignment is mechanically gated via `manage_issue_assignees` MCP tool. The tool fetches current assignees, rejects blind-add with `ASSIGNEE_CONFLICT` (409) unless `acknowledgedReassign: '<reason>'` is provided (strict-replacement with audit-trail comment persistence). Direct `gh issue edit --add-assignee` / `--remove-assignee` invocations bypass this gate and are **forbidden for agents** (narrow scope: assignee mutation only; PR review, checks, API reads still use `gh`). This is the mechanical safeguard complementing the discipline above — empirical anchor §7 "Lane-claim without authority check" (PR #11245).
71+
72+
### 6.5.1 Lane-Override Protocol (`[lane-override]`)
73+
74+
*(Codified per #11537 AC10, graduated from Discussion #11536 OQ6 resolution.)*
75+
76+
When a peer needs to override an existing `[lane-claim]` (e.g., operator-recommendation-via-prompt that wasn't visible to the original claimant, cross-family corrective-authorship per AGENTS.md §6.2.1, context-exhaustion handoff), use the `[lane-override]` primitive:
77+
78+
**Required A2A shape**:
79+
- Subject: `[lane-override] reclaiming #N from @<previous-claimant>`
80+
- Body: reason for override + cited source-of-authority (operator quote, peer A2A messageId, etc.) + scope-boundary statement
81+
- Recipient: `AGENT:*` broadcast + DM to previous claimant
82+
83+
**TTL: 2 hours** (aligned with standard session lifespan). After 2h, `[lane-override]` expires; the lane reverts to the original claimant's `[lane-claim]` (if still within its own TTL). If both the original `[lane-claim]` and the `[lane-override]` are TTL-expired, the lane falls through to the next claimant per timing order.
84+
85+
**Tool-side complement:** `manage_issue_assignees` with `acknowledgedReassign: '<reason>'` performs the mechanical strict-replacement; the audit-trail comment captures the reason as GitHub-visible artifact (per #11537 AC8 — reason must be persisted in a graph-readable surface, not transient event metadata).
86+
87+
**Anti-pattern guard:** `[lane-override]` is for legitimate corrective handoffs, NOT for racing-to-PR-by-asserting-override. If two peers both claim authority, escalate to §6.6 conflict-resolution hierarchy + operator if unresolved. The TTL exists to prevent permanent lock if the overriding agent crashes / gets stuck in a loop.
88+
6589
### 6.6 Source-of-Authority Collision Check
6690

6791
*(Codified per #11209 Option A-prime peer step 6.)*
@@ -107,6 +131,8 @@ The absence of subservience ("Helpful Assistant" regression drift) is not mere n
107131
- **Waiting for lane assignment:** Read the visible lane landscape and self-select based on independent judgment of what your domain context most enables. Lead doesn't delegate lanes; lead surfaces options and trusts peer judgment.
108132
- **Lane-claim without source-of-authority collision check (per §6.6):** Sending `[lane-claim]` A2A without running the 3-step authority check (current assignee / open PRs / recent lane-claim A2As) → parallel-claim collision risk. Empirical anchor: PR #11199 vs PR #11203 35-second-margin near-miss.
109133
- **Lane-claim for read-only sweep (over-triggering, per §6.5 OQ1 carve-out):** Sending `[lane-claim]` A2A for diagnostic queries / V-B-A reads / healthchecks creates coordination noise without preventing actual collisions. Write-operations only.
134+
- **`gh issue edit --add-assignee` / `--remove-assignee` bypass (per #11537):** Direct `gh` CLI invocation for assignee mutation bypasses the `manage_issue_assignees` MCP tool's precondition + post-verify gate (`requireUnassigned: true` default + `acknowledgedReassign: '<reason>'` strict-replacement override + audit-trail comment persistence). Narrow ban scope: ASSIGNEE MUTATION ONLY — PR review, checks, API reads, label management, project membership still use `gh`. Broader "no direct gh state mutation" policy is a separate high-blast Discussion. Empirical anchor: same PR #11245 pattern above (the bypass is the mechanical surface of the discipline-dressed-deference anti-pattern). Mirrors CLAUDE.md §11 "Bash Ban" pattern (forbidden bash redirection for file editing) at the assignee-mutation surface.
135+
- **Pre-V-B-A `[lane-claim]` (per #11537 AC2 + Discussion #11536 GPT V-B-A rejection of Option B):** Broadcasting `[lane-claim] taking #N (V-B-A pending)` reads as claim+disclaimer and conflicts with §6.6 authority hierarchy where `[lane-claim]` is Current Public Authority. Dilutes authority semantics + creates race-to-announcement incentive. Use `[lane-intent]` (narrow scope, non-authoritative, 2h TTL) for pre-V-B-A signal in collision-prone lanes only.
110136

111137
## 8. Halt Triggers (Machine-Checkable)
112138
- **Empty agreement:** Zero substantive contribution beyond "looks good" → force evidence-backed restatement OR explicit "alignment after checking X/Y/Z with residual risks named" OR halt.

.agents/skills/skills.manifest.json

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,17 @@
112112
"learn/guides/fundamentals/CodebaseOverview.md"
113113
]
114114
},
115+
"lane-intent": {
116+
"name": "lane-intent",
117+
"description": "Narrow, non-authoritative, TTL-bound pre-V-B-A signal for collision-prone / high-blast / long-V-B-A lanes (deep memory-mining, tech-debt-radar, multi-turn architectural V-B-A). Distinct from authoritative `[lane-claim]` (post-V-B-A). Triggers: Use this skill BEFORE broadcasting `[lane-intent] evaluating #N` to confirm scope-trigger qualifies — narrow scope, not blanket coverage. Do NOT auto-fire for short single-turn V-B-A where direct `[lane-claim]` after V-B-A suffices.",
118+
"routerByteBudget": 12,
119+
"payloadBudget": 80000,
120+
"claudeSymlinkRequired": true,
121+
"downstreamDocsTargets": [
122+
"learn/agentos/ProgressiveDisclosureSkills.md",
123+
"learn/guides/fundamentals/CodebaseOverview.md"
124+
]
125+
},
115126
"lead-role": {
116127
"name": "lead-role",
117128
"description": "Switch into relaxed-planning + dialogue-first mindset when delegated lead role for coordination. Suspends Auto Mode velocity-bias for the duration. Triggers: Use this skill IMMEDIATELY when the user delegates lead with explicit phrases (\"you take the lead\", \"coordinate the team\", \"lead this phase\", \"drive the next planning step\", \"chief-architect\" when scope is swarm/substrate/roadmap/multi-ticket), OR when AGENTS.md §22 mailbox check surfaces a valid `lead-role-baton`, OR when you have just authored a substrate-shaped ticket about to enter implementation, OR via direct /lead-role invocation.",

.claude/skills/lane-intent

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../../.agents/skills/lane-intent

ai/mcp/server/github-workflow/openapi.yaml

Lines changed: 41 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -553,22 +553,30 @@ paths:
553553

554554
/issues/{issue_number}/assignees/manage:
555555
post:
556-
summary: Manage Issue Assignees (Add or Remove)
556+
summary: Manage Issue Assignees (Single Guarded MCP Operation — Add or Remove)
557557
operationId: manage_issue_assignees
558558
x-pass-as-object: true
559559
x-annotations:
560560
readOnlyHint: false
561561
description: |
562562
Unified tool for assigning or unassigning users from a GitHub issue.
563+
Performs a single guarded operation with precondition checking.
563564
564-
**Action: 'add'**
565-
- Assigns one or more users.
565+
**Action: 'add' — gated**
566+
- Default `requireUnassigned: true` rejects adding to already occupied issues with
567+
`ASSIGNEE_CONFLICT` (HTTP 409).
568+
- To override an occupied issue, pass `acknowledgedReassign: '<reason>'` for strict replacement.
569+
This clears existing assignees, assigns the new set, and posts an audit-trail comment with the reason.
570+
- `requireUnassigned: false` allows legacy blind-add.
566571
567-
**Action: 'remove'**
568-
- Unassigns one or more users.
572+
**Action: 'remove' — ungated**
573+
- Unassigns one or more users (the named set).
574+
575+
**Empty assignees array (`action: 'add'`, `assignees: []`) — clear mode**
576+
- Clears all current assignees safely.
569577
570578
**Special Values:**
571-
- `@me`: Resolves to the authenticated GitHub user. Use this instead of hardcoding usernames.
579+
- `@me`: Resolves to the authenticated GitHub user.
572580
573581
**Permission Check:**
574582
Requires `ADMIN`, `MAINTAIN`, or `WRITE` permissions. Returns 403 otherwise.
@@ -601,9 +609,26 @@ paths:
601609
type: string
602610
description: An array of GitHub user logins. Use `@me` to assign/unassign the authenticated user.
603611
example: ["@me"]
612+
requireUnassigned:
613+
type: boolean
614+
default: true
615+
description: |
616+
Precondition gate for `action: 'add'`. When `true` (default), the tool fetches
617+
current assignees and rejects with `ASSIGNEE_CONFLICT` (HTTP 409) if non-empty,
618+
unless `acknowledgedReassign` is provided. Set to `false` to bypass the gate
619+
(legacy blind-add path; new callers should not rely on this).
620+
example: true
621+
acknowledgedReassign:
622+
type: string
623+
description: |
624+
Reason-bearing override for strict-replacement reassignment. When provided
625+
alongside `action: 'add'` on an occupied issue, the tool clears existing
626+
assignees, assigns the new set, and posts an audit-trail comment on the
627+
issue capturing this reason. Required when overriding an existing assignment.
628+
example: "context-exhaustion handoff from peer who session-sunsetted"
604629
responses:
605630
'200':
606-
description: Assignees updated successfully.
631+
description: Assignees updated successfully. Response includes `verifiedAssignees` (post-verify state) and, for override paths, `acknowledgedReassign` + `previousAssignees`.
607632
content:
608633
application/json:
609634
schema:
@@ -620,6 +645,15 @@ paths:
620645
application/json:
621646
schema:
622647
$ref: '#/components/schemas/ErrorResponse'
648+
'409':
649+
description: |
650+
`ASSIGNEE_CONFLICT` — precondition gate rejected blind-add on an occupied issue.
651+
Response includes `currentAssignees` (existing) + `attemptedAssignees` (requested)
652+
for caller introspection. To proceed, retry with `acknowledgedReassign: '<reason>'`.
653+
content:
654+
application/json:
655+
schema:
656+
$ref: '#/components/schemas/ErrorResponse'
623657
'500':
624658
description: Internal server error.
625659
content:

0 commit comments

Comments
 (0)