fix(linear-issue): honor parent param on update action (ARM-128) - #76
Conversation
The linear_issue tool's update action accepted a parent parameter via its TypeBox schema, returned success: true, but never actually forwarded parentId to the Linear issueUpdate mutation. Reparenting silently no-op'd, which is worse than rejecting the request — agents thought their reorganizations had landed when they hadn't. The create path was correct; only update was missing the input mapping. Changes: - Add params.parent handling to updateIssue, mirroring createIssue. - Treat empty string or null as 'unparent' (sets parentId: null on IssueUpdateInput, which Linear interprets as removing the parent link). - Update the schema description to document update support and the empty-string unparent escape hatch. Verified end-to-end against the live Linear API (14 assertions): create under parent A, reparent to B via update, unparent via empty string, reparent + unparent via null, plus children.nodes consistency on every parent before/after each transition. Fixes ARM-128.
ARM-128 Bug: `linear_issue` update action silently ignores `parent` field
SummaryThe The Impact
ReproductionHit during the ARM-5 compliance epic restructuring on 2026-04-07:
Meanwhile ARM-124–127, which were created the same session with Expected BehaviorOne of:
Tool Schema NoteThe current tool schema documents
If the intent is truly "create only," the parameter should either be removed from the update action's accepted params, or the update path should return a validation error when it's passed. Entry PointsThe
Definition of Done
Related
|
Summary
Fixes ARM-128. The `linear_issue` tool's `update` action accepted a `parent` parameter via its TypeBox schema and returned `success: true`, but never actually forwarded `parentId` to the Linear `issueUpdate` mutation. Reparenting silently no-op'd, so agents thought their reorganizations had landed when they hadn't. The bug was specific to the update path — `create` worked correctly.
Root cause
`updateIssue` in `src/tools/linear-issue.ts` builds an `input` object from the params and forwards it to the `issueUpdate` mutation. Every other field (title, description, state, assignee, labels, dueDate, etc.) had a corresponding `if (params.X) input.Y = …` line. `parent` was missing entirely. `createIssue` had the correct mapping; it just wasn't mirrored on the update path.
Fix
```ts
if (params.parent !== undefined) {
// Empty string or null → unparent. Otherwise resolve the identifier (e.g. ENG-100) → UUID.
input.parentId = params.parent === "" || params.parent === null ? null : await resolveIssueId(params.parent);
}
```
Verification
Ran an end-to-end smoke test against the live Linear API using the patched module. 14 assertions, all green:
```
[smoke] Creating parent A...
✓ parent A created: ARM-129
[smoke] Creating parent B...
✓ parent B created: ARM-130
[smoke] Creating child under parent A (via create path)...
✓ child created: ARM-131
[smoke] Verify create path: child has parent A...
✓ child.parent === ARM-129
✓ parent A children include ARM-131
[smoke] Reparenting child A → B via UPDATE (the actual bug fix)...
✓ update returned success
✓ child.parent now === ARM-130
✓ parent A no longer includes ARM-131
✓ parent B now includes ARM-131
[smoke] Unparenting via empty string...
✓ unparent (empty string) returned success
✓ child.parent === null after empty-string unparent
✓ parent B no longer includes ARM-131 after unparent
[smoke] Reparenting back to A, then unparenting via null...
✓ re-parented to ARM-129 for null test
✓ unparent (null) returned success
✓ child.parent === null after null unparent
[smoke] ALL ASSERTIONS PASSED ✅
```
Test coverage:
Also passed:
Definition of Done (from ARM-128)
Notes
The fix won't take effect for currently-running agent sessions until the new image is built and they reconnect — the existing pi runtime still has the buggy version compiled in. Verification above used the patched module loaded directly, so it exercises the actual code path that will ship.