diff --git a/docs/release-control/v6/internal/subsystems/patrol-intelligence.md b/docs/release-control/v6/internal/subsystems/patrol-intelligence.md index 13fec92fa..4abcc812c 100644 --- a/docs/release-control/v6/internal/subsystems/patrol-intelligence.md +++ b/docs/release-control/v6/internal/subsystems/patrol-intelligence.md @@ -173,6 +173,10 @@ formatting future schedule timestamps through generic relative-time helpers; otherwise the findings footer can contradict the header by rendering the same next scheduled patrol as `just now` while the main Patrol shell correctly shows a multi-hour countdown. +That footer must also use the canonical Patrol recency label rather than a +generic `Last:` prefix, so scoped-only recent activity is rendered as +`Last activity` and does not silently revert to patrol/full-verification +language in the findings surface. When Patrol is currently running, that strip should still stay factual rather than switching to another verdict label: the runtime may add an explicit in-progress indicator, but the primary activity label remains recent activity diff --git a/frontend-modern/src/components/AI/FindingsPanel.tsx b/frontend-modern/src/components/AI/FindingsPanel.tsx index 3c2b2cd09..7ab018bdf 100644 --- a/frontend-modern/src/components/AI/FindingsPanel.tsx +++ b/frontend-modern/src/components/AI/FindingsPanel.tsx @@ -61,6 +61,7 @@ interface FindingsPanelProps { showControls?: boolean; nextPatrolAt?: string; lastPatrolAt?: string; + lastPatrolLabel?: string; patrolIntervalMs?: number; scopeResourceIds?: string[]; scopeResourceTypes?: string[]; @@ -1161,7 +1162,7 @@ export const FindingsPanel: Component = (props) => { d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" /> - Last: {formatTime(props.lastPatrolAt!)} + {props.lastPatrolLabel ?? 'Last'}: {formatTime(props.lastPatrolAt!)} diff --git a/frontend-modern/src/components/AI/__tests__/FindingsPanel.test.ts b/frontend-modern/src/components/AI/__tests__/FindingsPanel.test.ts index 14aaff4ff..a5a932e21 100644 --- a/frontend-modern/src/components/AI/__tests__/FindingsPanel.test.ts +++ b/frontend-modern/src/components/AI/__tests__/FindingsPanel.test.ts @@ -163,6 +163,11 @@ describe('aiFindingPresentation', () => { expect(findingsPanelSource).toContain(''); expect(findingsPanelSource).not.toContain('Next: {formatTime(props.nextPatrolAt!)}'); }); + + it('uses the supplied canonical patrol recency label in the footer', () => { + expect(findingsPanelSource).toContain("{props.lastPatrolLabel ?? 'Last'}: {formatTime(props.lastPatrolAt!)}"); + expect(findingsPanelSource).not.toContain('Last: {formatTime(props.lastPatrolAt!)}'); + }); }); describe('sourceColors', () => { diff --git a/frontend-modern/src/features/patrol/PatrolIntelligenceWorkspace.tsx b/frontend-modern/src/features/patrol/PatrolIntelligenceWorkspace.tsx index 502978d42..256377243 100644 --- a/frontend-modern/src/features/patrol/PatrolIntelligenceWorkspace.tsx +++ b/frontend-modern/src/features/patrol/PatrolIntelligenceWorkspace.tsx @@ -4,10 +4,16 @@ import { ApprovalBanner, PatrolStatusBar, RunHistoryPanel } from '@/components/p import { getFindingSeverityToneClasses } from '@/utils/aiFindingPresentation'; import { formatRelativeTime } from '@/utils/format'; import { formatTriggerReason } from '@/utils/patrolFormat'; +import { getPatrolRecencyPresentation } from '@/utils/patrolSummaryPresentation'; import type { PatrolIntelligenceState } from './usePatrolIntelligenceState'; export function PatrolIntelligenceWorkspace(props: { state: PatrolIntelligenceState }) { const state = props.state; + const recency = () => + getPatrolRecencyPresentation({ + runs: state.patrolRunHistory() ?? [], + lastPatrolAt: state.patrolStatus()?.last_patrol_at, + }); return ( <> @@ -96,6 +102,7 @@ export function PatrolIntelligenceWorkspace(props: { state: PatrolIntelligenceSt