diff --git a/apps/frontend/src/renderer/components/GitHubIssues.tsx b/apps/frontend/src/renderer/components/GitHubIssues.tsx
index 1c48baad..341cb6e3 100644
--- a/apps/frontend/src/renderer/components/GitHubIssues.tsx
+++ b/apps/frontend/src/renderer/components/GitHubIssues.tsx
@@ -16,6 +16,7 @@ import {
useAITriage,
useTriageMode,
useMetrics,
+ useMutations,
} from "./github-issues/hooks";
import { useAnalyzePreview } from "./github-issues/hooks/useAnalyzePreview";
import {
@@ -155,6 +156,51 @@ export function GitHubIssues({ onOpenSettings, onNavigateToTask }: GitHubIssuesP
// Metrics
const { metrics, timeWindow: metricsTimeWindow, isLoading: isMetricsLoading, computeMetrics, setTimeWindow: setMetricsTimeWindow } = useMetrics();
+ // Issue mutations (edit, close, reopen, comment, labels, assignees)
+ const mutations = useMutations(selectedProject?.id ?? '');
+
+ // Wrapped mutation callbacks bound to selected issue
+ const handleEditTitle = useCallback(
+ async (title: string) => { if (selectedIssue) await mutations.editTitle(selectedIssue.number, title); },
+ [selectedIssue, mutations],
+ );
+ const handleEditBody = useCallback(
+ async (body: string) => { if (selectedIssue) await mutations.editBody(selectedIssue.number, body); },
+ [selectedIssue, mutations],
+ );
+ const handleCloseIssue = useCallback(
+ async (comment?: string) => {
+ if (!selectedIssue) return;
+ if (comment) await mutations.addComment(selectedIssue.number, comment);
+ await mutations.closeIssue(selectedIssue.number);
+ },
+ [selectedIssue, mutations],
+ );
+ const handleReopenIssue = useCallback(
+ async () => { if (selectedIssue) await mutations.reopenIssue(selectedIssue.number); },
+ [selectedIssue, mutations],
+ );
+ const handleAddComment = useCallback(
+ async (body: string) => { if (selectedIssue) await mutations.addComment(selectedIssue.number, body); },
+ [selectedIssue, mutations],
+ );
+ const handleAddLabels = useCallback(
+ async (labels: string[]) => { if (selectedIssue) await mutations.addLabels(selectedIssue.number, labels); },
+ [selectedIssue, mutations],
+ );
+ const handleRemoveLabels = useCallback(
+ async (labels: string[]) => { if (selectedIssue) await mutations.removeLabels(selectedIssue.number, labels); },
+ [selectedIssue, mutations],
+ );
+ const handleAddAssignees = useCallback(
+ async (logins: string[]) => { if (selectedIssue) await mutations.addAssignees(selectedIssue.number, logins); },
+ [selectedIssue, mutations],
+ );
+ const handleRemoveAssignees = useCallback(
+ async (logins: string[]) => { if (selectedIssue) await mutations.removeAssignees(selectedIssue.number, logins); },
+ [selectedIssue, mutations],
+ );
+
// Compute metrics on mount when enrichment is loaded
useEffect(() => {
if (selectedProject?.id && enrichmentLoaded) {
@@ -324,6 +370,15 @@ export function GitHubIssues({ onOpenSettings, onNavigateToTask }: GitHubIssuesP
onImproveIssue={() => aiTriage.runEnrichment(selectedIssue.number)}
onSplitIssue={() => aiTriage.runSplitSuggestion(selectedIssue.number)}
isAIBusy={aiTriage.isTriaging}
+ onEditTitle={handleEditTitle}
+ onEditBody={handleEditBody}
+ onClose={handleCloseIssue}
+ onReopen={handleReopenIssue}
+ onComment={handleAddComment}
+ onAddLabels={handleAddLabels}
+ onRemoveLabels={handleRemoveLabels}
+ onAddAssignees={handleAddAssignees}
+ onRemoveAssignees={handleRemoveAssignees}
/>
) : (
diff --git a/docs/gap-tracker.md b/docs/gap-tracker.md
index 973b6bd6..db4c03a6 100644
--- a/docs/gap-tracker.md
+++ b/docs/gap-tracker.md
@@ -3,7 +3,7 @@
**Branch:** `terminal/enhancement-issues-tab`
**Created:** 2026-02-12
**Total Gaps:** 41 confirmed (from triple-verified audit)
-**Status:** 4 / 41 complete
+**Status:** 5 / 41 complete
---
@@ -31,17 +31,16 @@ Each gap has: ID, description, status, files to modify, doc reference, test stat
## TIER 1 — Critical Wiring (Components built but not connected)
### GAP-01: `useMutations` hook not called in GitHubIssues.tsx
-- **Status:** `PENDING`
+- **Status:** `DONE`
- **Priority:** MUST-FIX
- **Scope:** Medium
- **Doc ref:** Phase 5 PRD > US-4 > AC-4.7; Phase 5 impl plan WP-4 Step 4.3
-- **Files to modify:** `renderer/components/GitHubIssues.tsx`
-- **Source hook:** `hooks/useMutations.ts` — returns editTitle, editBody, closeIssue, reopenIssue, addComment, addLabels, removeLabels, addAssignees, removeAssignees
-- **Fix:** Import useMutations from hooks barrel, call `useMutations(selectedProject?.id ?? '')`, pass all callbacks to `` as onEditTitle, onEditBody, onAddLabels, onRemoveLabels, onAddAssignees, onRemoveAssignees, onClose, onReopen, onComment
-- **Tests:** Verify mutation callbacks are passed to IssueDetail
-- **Test status:** `PENDING`
+- **Files modified:** `GitHubIssues.tsx`
+- **Fix:** Imported useMutations from hooks barrel, called with project ID, created 9 wrapped useCallback handlers bound to selectedIssue.number, passed all to IssueDetail (onEditTitle, onEditBody, onClose, onReopen, onComment, onAddLabels, onRemoveLabels, onAddAssignees, onRemoveAssignees)
+- **Tests:** IssueDetail integration tests pass (7 tests), lint clean
+- **Test status:** `PASS`
- **Depends on:** None
-- **Commit:** —
+- **Commit:** GAP-01
### GAP-02: InlineEditor not used for title editing in IssueDetail.tsx
- **Status:** `PENDING`
@@ -551,6 +550,7 @@ Each gap has: ID, description, status, files to modify, doc reference, test stat
| 2026-02-12 | GAP-17 | DONE — risksEdgeCases section added to EnrichmentPanel, i18n keys added EN+FR, 10 tests pass | GAP-17 |
| 2026-02-12 | GAP-24 | DONE — 3 panels changed to `` with i18n aria-label, lint clean | GAP-24 |
| 2026-02-12 | GAP-38 | DONE — aria-labels on AI buttons (EnrichmentPanel + BulkActionBar), 18 tests pass | GAP-38 |
+| 2026-02-12 | GAP-01 | DONE — useMutations wired in GitHubIssues.tsx, 9 callbacks passed to IssueDetail | GAP-01 |
---