Suspect linkage, corrections and fix-loop edges
## Requirement (verbatim)
3. "Suspect linkage: the monitor's release/commit when present; else deploys in the first-seen window narrowed by stack-frame paths against their diffs. Store confidence, show it, let an operator correct it. Writes the ledger's incident_linked state on the origin outcomes."
From 4 (verbatim): "The fix PR references the incident; the incident closing after the fix's deploy marks the fixer survived and the origin incident_linked."
Settled: D1 ledger edges are recorded as pending `production_qa_edges` until epic 12243 lands. Relaxed AC-20 (operator R3, flagged for Finish): this epic writes the facts `resolved_by_fix` (fixer) and `incident_linked` (origins); 12243's window decides `survived` — "the ledger receives the facts". A8: project admins (`projects:edit` on the incident's project) correct suspect links.
Design: architecture artifact of Task 12249, §7 (bases, confidences, corrections, incident_linked, fix loop), §4 linkage signatures, §11 task-detail "Incident" chip.
## Scope (architecture C6)
- `linkage.compute` on opened/reopened: release basis (`high`: `commit_sha` or ≥7-hex `release` contained in a production anchor's `deployment_commits`; a PR merge sha → that PR alone); deployment basis (`high`, incident with `deployment_id`); window basis (anchors finished in `[first_seen−24h, first_seen]`, latest 5; `task_pr_changes.files` ∩ normalised stack-frame paths, suffix match, `in_app` first: overlap → `medium` `window_paths`, else `low`); none → "No suspect". Recompute never overwrites a decided row.
- Corrections: `PATCH /api/incidents/{id}/suspects/{sid}` `{state}` and `POST /api/incidents/{id}/suspects` `{repo_path, pr_number}` → `operator`/`high`/`confirmed`, actor + time stored; `projects:edit` required. UI controls on the incident Suspects tab (confirm / dismiss / add), showing who and when.
- Edges: `incident_linked` for confirmed ∪ suggested-high on open/reopen/correction; dismissal sets `revoked_at`. `on_resolved`: an `incident_tasks` task (fix/triage) whose PR is in an anchor finished before `resolved_at` → `resolved_by_fix`; `on_deployment` re-checks already-resolved incidents (order-independent). Incident detail Ledger tab shows "Pending" until applied.
- Task detail: "Incident" chip (link to `/incidents/:id`) when an `incident_tasks` row exists.
Credentials & reach:
- UI checks on dev — `org/console/dev-login` (org Admin), `https://dev.jaah.ai` — credential **verified**; environment **deferred** for this node (operator R4: run from a tailnet node)
- AC-29 gates — worktree only — **verified**
Out of scope: Do NOT create or own `task_outcomes` or write to it (the ledger applier child, after 12243). Do NOT add any scoring or ranking logic beyond the suspect confidence words. Do NOT add a per-task deploy panel (D7; the chip is allowed). Epic out of scope (verbatim): "building an APM or log store; replacing the customer's monitor; auto-merging a revert without the project's policy; any scoring or ranking logic (the outcome ledger epic reads the states this epic writes)."
Done means:
- AC-12: "an incident whose payload names a release or commit links to the production deployment(s) containing that commit and their PRs, with confidence `high`. The Incidents row shows the suspect PRs and the confidence as a word, never as colour alone." — tests with seeded deployments/commits; live: Sentry sample with `release` = latest deploy sha once ingestion is live.
- AC-13: "an incident without a release links to production deploys in its first-seen window. Deploys whose diff touches a file in the stack frames rank above those that do not, and confidence is lower than release-based. With no deploys in the window, it shows 'no suspect'." — tests for overlap/no-overlap/empty window.
- AC-14: "a project admin can confirm, dismiss, or add a suspect PR from the incident row. The change persists, shows who made it and when, and is what the ledger edge uses." — route + UI test: dismiss, reload, still dismissed with actor shown; edge revoked; a user without `projects:edit` gets 403.
- AC-20 (pending form): "the same transitions are recorded as pending ledger edges, visible on the incident detail" — test: fix task's PR in an anchor before resolve → `resolved_by_fix` edge; origins → `incident_linked`; order-independent when the deploy is recorded after the resolve.
- AC-26: linkage and edges written with `production_qa` OFF — test.
- AC-29: `./dc check quick` green; changed-area tests green; merge lane full gate green.
Activity
- Draft
- Ready