Phase 2 follow-up.
CreateSaasIncident accepts an initial set of finding_ids to link, but there is no post-create RPC to add or remove findings. Operators today have to recreate an incident if they want to re-scope its linked findings.
Scope
- Add Connect RPCs:
AddFindingToSaasIncident(incident_id, finding_id)
RemoveFindingFromSaasIncident(incident_id, finding_id)
- Enforce tenant scoping and reuse the
maxSaasIncidentLinkedFindings cap from internal/bootstrap/saas_dr.go.
- Emit timeline events (
DETECTION kind, 'Finding linked' / 'Finding unlinked') and writeCompatAudit rows.
- Populate
linked_by_user_id on the link row when adding.
- Frontend: surface a 'Link finding' affordance in
apps/web/components/incidents/incident-detail-page.tsx and unlink controls on each linked finding card.
Acceptance
- Unit tests cover tenant isolation, the cap, idempotent add (ON CONFLICT DO NOTHING), and unlink-of-unlinked rejection.
- Audit log rows present in
compat_audit_log_entries.
- FE can fully manage the linked-finding set without recreating the incident.
Phase 2 follow-up.
CreateSaasIncidentaccepts an initial set offinding_idsto link, but there is no post-create RPC to add or remove findings. Operators today have to recreate an incident if they want to re-scope its linked findings.Scope
AddFindingToSaasIncident(incident_id, finding_id)RemoveFindingFromSaasIncident(incident_id, finding_id)maxSaasIncidentLinkedFindingscap frominternal/bootstrap/saas_dr.go.DETECTIONkind, 'Finding linked' / 'Finding unlinked') andwriteCompatAuditrows.linked_by_user_idon the link row when adding.apps/web/components/incidents/incident-detail-page.tsxand unlink controls on each linked finding card.Acceptance
compat_audit_log_entries.