Update Patrol runtime action recovery guidance

This commit is contained in:
rcourtman 2026-05-07 16:31:42 +01:00
parent f5a59661fe
commit 8061670b10
4 changed files with 35 additions and 5 deletions

View file

@ -1231,8 +1231,9 @@ Patrol actually succeeds or resolves them for a Patrol-owned reason.
Because those findings represent Patrol blindness rather than operator-triaged
infrastructure noise, the Patrol runtime must also reject manual acknowledge,
snooze, dismiss, resolve, and suppress actions against synthetic `ai-service`
runtime findings. The canonical recovery path is to correct AI/provider
configuration and let Patrol re-evaluate the runtime condition on the next run.
runtime findings. The canonical recovery path is to correct Patrol provider
configuration in Assistant & Patrol settings and let Patrol re-evaluate the
runtime condition on the next run.
The shared findings lifecycle must also treat a regressed issue as a new active
occurrence. When a resolved finding reappears, `internal/ai/findings.go` must
clear any stale acknowledgement timestamp from the prior occurrence instead of

View file

@ -479,8 +479,8 @@ That same contract must fail closed on manual lifecycle controls too. Patrol
runtime findings are Patrol-owned impairment signals, not ordinary estate
findings, so the findings list must not offer generic acknowledge, snooze,
dismiss, resolve, or suppress controls for them. The correct operator path is
to fix Patrol provider configuration and rerun Patrol, optionally adding context
notes, rather than hiding the runtime issue.
to fix Patrol provider configuration in Assistant & Patrol settings and rerun
Patrol, optionally adding context notes, rather than hiding the runtime issue.
That same runtime-versus-infrastructure split must carry through the summary
metrics strip as well. When Patrol-owned runtime issues are active, the
supporting metrics must stop counting them under generic infrastructure

View file

@ -31,7 +31,7 @@ func patrolFindingUsesSyntheticRuntimeResource(f *Finding) bool {
func patrolRuntimeFindingManualActionError(action string) error {
return fmt.Errorf(
"Patrol runtime findings cannot be %s manually; update AI settings and rerun Patrol",
"Patrol runtime findings cannot be %s manually; fix Patrol provider configuration in Assistant & Patrol settings and rerun Patrol",
action,
)
}

View file

@ -111,6 +111,9 @@ func TestPatrolService_DismissFinding_RejectsPatrolRuntimeFinding(t *testing.T)
if got := err.Error(); !strings.Contains(got, "cannot be dismissed manually") {
t.Fatalf("unexpected error: %q", got)
}
if got := err.Error(); !strings.Contains(got, "Assistant & Patrol settings") {
t.Fatalf("dismissal guidance must point to Assistant & Patrol settings: %q", got)
}
stored := ps.findings.Get("runtime-1")
if stored == nil {
@ -121,6 +124,32 @@ func TestPatrolService_DismissFinding_RejectsPatrolRuntimeFinding(t *testing.T)
}
}
func TestPatrolService_RejectManualActionForRuntimeFindingUsesProviderSettingsGuidance(t *testing.T) {
ps := NewPatrolService(nil, nil)
ps.findings.Add(&Finding{
ID: "runtime-1",
Key: patrolRuntimeFindingKey,
Severity: FindingSeverityWarning,
Category: FindingCategoryReliability,
ResourceID: patrolRuntimeResourceID,
ResourceName: "Pulse Patrol Service",
ResourceType: "service",
Title: "Pulse Patrol: Provider not ready",
})
err := ps.RejectManualActionForRuntimeFinding("runtime-1", "acknowledged")
if err == nil {
t.Fatal("expected Patrol runtime finding manual action to be rejected")
}
got := err.Error()
if !strings.Contains(got, "fix Patrol provider configuration in Assistant & Patrol settings") {
t.Fatalf("manual action guidance = %q", got)
}
if strings.Contains(got, "AI settings") {
t.Fatalf("manual action guidance must not reference legacy AI settings: %q", got)
}
}
func TestPatrolFindingCreatorAdapter_IsActionable(t *testing.T) {
ps := NewPatrolService(nil, nil)