mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-05-13 15:28:38 +00:00
Extract patrol intelligence surface
This commit is contained in:
parent
d10aedd419
commit
dc7dbbb48b
6 changed files with 1596 additions and 1555 deletions
|
|
@ -78,7 +78,7 @@ Own canonical runtime payload shapes between backend and frontend.
|
|||
4. Route unified resource sensitivity, routing, and `aiSafeSummary` payload changes through `internal/api/resources.go`, `internal/api/contract_test.go`, and the canonical frontend resource consumer proofs together; resource governance metadata must not ship as an API-only or frontend-only heuristic
|
||||
5. Route unified-resource action, lifecycle, and export audit reads through `internal/api/activity_audit_handlers.go`, `internal/api/router_routes_licensing.go`, and `internal/api/contract_test.go` together so the control-plane execution trail stays on a governed API contract instead of a store-only shape
|
||||
6. Route dedicated unified-resource timeline and facet-bundle reads through `frontend-modern/src/api/resources.ts`, `internal/api/resources.go`, and `internal/api/contract_test.go` together so the backend facet contract and the frontend client stay aligned on one timeline-first surface, while capability and relationship detail stays backend-owned for AI correlation and change detection
|
||||
7. Route canonical AI intelligence summary and resource-intelligence reads through `frontend-modern/src/api/ai.ts`, `frontend-modern/src/stores/aiIntelligence.ts`, `frontend-modern/src/pages/AIIntelligence.tsx`, `internal/api/ai_handlers.go`, and `internal/api/contract_test.go` together so the summary card, store state, and backend payload stay aligned on one governed surface, including the canonical recent-changes slice
|
||||
7. Route canonical AI intelligence summary and resource-intelligence reads through `frontend-modern/src/api/ai.ts`, `frontend-modern/src/stores/aiIntelligence.ts`, `frontend-modern/src/features/patrol/PatrolIntelligenceSurface.tsx`, `frontend-modern/src/pages/AIIntelligence.tsx`, `internal/api/ai_handlers.go`, and `internal/api/contract_test.go` together so the summary card, store state, route shell, and backend payload stay aligned on one governed surface, including the canonical recent-changes slice
|
||||
while keeping the learning counters backend-only coverage, so the summary page keeps Patrol health and findings primary and renders timeline, correlation, and policy-posture data as secondary investigation context rather than as a separate headline product metric
|
||||
and the shared `frontend-modern/src/components/Infrastructure/ResourceChangeSummary.tsx` card, so canonical recent-change timelines stay rendered through one governed frontend card instead of separate page-local list loops
|
||||
and the shared `frontend-modern/src/utils/resourceChangePresentation.ts` formatter used by the summary page and resource drawer, so canonical change wording does not drift across surfaces
|
||||
|
|
|
|||
|
|
@ -15,26 +15,27 @@
|
|||
|
||||
## Purpose
|
||||
|
||||
Own the Patrol intelligence page, its local state orchestration, findings and
|
||||
approval presentation, run-history rendering, and Patrol-specific presentation
|
||||
helpers.
|
||||
Own the Patrol intelligence route shell, feature surface, local state
|
||||
orchestration, findings and approval presentation, run-history rendering, and
|
||||
Patrol-specific presentation helpers.
|
||||
|
||||
## Canonical Files
|
||||
|
||||
1. `frontend-modern/src/pages/AIIntelligence.tsx`
|
||||
2. `frontend-modern/src/stores/aiIntelligence.ts`
|
||||
3. `frontend-modern/src/types/aiIntelligence.ts`
|
||||
4. `frontend-modern/src/components/AI/FindingsPanel.tsx`
|
||||
5. `frontend-modern/src/components/Brand/PulsePatrolLogo.tsx`
|
||||
6. `frontend-modern/src/components/patrol/`
|
||||
7. `frontend-modern/src/utils/aiFindingPresentation.ts`
|
||||
8. `frontend-modern/src/utils/approvalRiskPresentation.ts`
|
||||
9. `frontend-modern/src/utils/findingAlertIdentity.ts`
|
||||
10. `frontend-modern/src/utils/patrolEmptyStatePresentation.ts`
|
||||
11. `frontend-modern/src/utils/patrolFormat.ts`
|
||||
12. `frontend-modern/src/utils/patrolRunPresentation.ts`
|
||||
13. `frontend-modern/src/utils/patrolSummaryPresentation.ts`
|
||||
14. `frontend-modern/src/utils/textPresentation.ts`
|
||||
1. `frontend-modern/src/features/patrol/PatrolIntelligenceSurface.tsx`
|
||||
2. `frontend-modern/src/pages/AIIntelligence.tsx`
|
||||
3. `frontend-modern/src/stores/aiIntelligence.ts`
|
||||
4. `frontend-modern/src/types/aiIntelligence.ts`
|
||||
5. `frontend-modern/src/components/AI/FindingsPanel.tsx`
|
||||
6. `frontend-modern/src/components/Brand/PulsePatrolLogo.tsx`
|
||||
7. `frontend-modern/src/components/patrol/`
|
||||
8. `frontend-modern/src/utils/aiFindingPresentation.ts`
|
||||
9. `frontend-modern/src/utils/approvalRiskPresentation.ts`
|
||||
10. `frontend-modern/src/utils/findingAlertIdentity.ts`
|
||||
11. `frontend-modern/src/utils/patrolEmptyStatePresentation.ts`
|
||||
12. `frontend-modern/src/utils/patrolFormat.ts`
|
||||
13. `frontend-modern/src/utils/patrolRunPresentation.ts`
|
||||
14. `frontend-modern/src/utils/patrolSummaryPresentation.ts`
|
||||
15. `frontend-modern/src/utils/textPresentation.ts`
|
||||
|
||||
## Shared Boundaries
|
||||
|
||||
|
|
@ -42,7 +43,7 @@ helpers.
|
|||
|
||||
## Extension Points
|
||||
|
||||
1. Add or change Patrol page orchestration through `frontend-modern/src/pages/AIIntelligence.tsx` and `frontend-modern/src/stores/aiIntelligence.ts`
|
||||
1. Add or change Patrol page orchestration through `frontend-modern/src/features/patrol/PatrolIntelligenceSurface.tsx`, keep `frontend-modern/src/pages/AIIntelligence.tsx` as the route shell, and update `frontend-modern/src/stores/aiIntelligence.ts` together
|
||||
2. Add or change Patrol findings, approvals, investigation, or run-history presentation through `frontend-modern/src/components/AI/FindingsPanel.tsx` and `frontend-modern/src/components/patrol/`
|
||||
3. Keep Patrol and chat identifier-label presentation aligned through the shared `frontend-modern/src/utils/textPresentation.ts`
|
||||
4. Keep Patrol and chat stream-matching / mention dedupe aligned through the shared `frontend-modern/src/utils/chatIdentifiers.ts`
|
||||
|
|
@ -68,6 +69,12 @@ surface for Patrol intelligence. This contract now owns that orchestration and
|
|||
presentation boundary while leaving shared transport and payload-shape
|
||||
ownership in the governed AI runtime and API contract surfaces.
|
||||
|
||||
The route file `frontend-modern/src/pages/AIIntelligence.tsx` is now also a
|
||||
thin shell that delegates to the feature-owned
|
||||
`frontend-modern/src/features/patrol/PatrolIntelligenceSurface.tsx`, so Patrol
|
||||
runtime state and presentation no longer accumulate directly in the route
|
||||
component itself.
|
||||
|
||||
Patrol finding state must now also consume the canonical camelCase
|
||||
`alertIdentifier` field and pending-approval expiry metadata end to end.
|
||||
Frontend Patrol helpers may not keep shadow `alert_identifier` fallbacks or
|
||||
|
|
|
|||
|
|
@ -19,6 +19,8 @@ import infrastructureSelectorComponentSource from '@/components/shared/Infrastru
|
|||
import workloadsLinkSource from '@/components/Infrastructure/workloadsLink.ts?raw';
|
||||
import unifiedResourceTableSource from '@/components/Infrastructure/UnifiedResourceTable.tsx?raw';
|
||||
import thresholdsTableSource from '@/components/Alerts/ThresholdsTable.tsx?raw';
|
||||
import alertsConfigurationSurfaceSource from '@/features/alerts/AlertsConfigurationSurface.tsx?raw';
|
||||
import thresholdsDataHookSource from '@/features/alerts/thresholds/hooks/useThresholdsData.ts?raw';
|
||||
import collapsibleSectionSource from '@/components/Alerts/Thresholds/sections/CollapsibleSection.tsx?raw';
|
||||
import alertThresholdsPresentationSource from '@/utils/alertThresholdsPresentation.ts?raw';
|
||||
import alertThresholdsSectionPresentationSource from '@/utils/alertThresholdsSectionPresentation.ts?raw';
|
||||
|
|
@ -29,6 +31,7 @@ import reportingPanelSource from '../ReportingPanel.tsx?raw';
|
|||
import updatesSettingsPanelSource from '../UpdatesSettingsPanel.tsx?raw';
|
||||
import suggestProfileModalSource from '../SuggestProfileModal.tsx?raw';
|
||||
import aiIntelligenceSource from '@/pages/AIIntelligence.tsx?raw';
|
||||
import patrolIntelligenceSurfaceSource from '@/features/patrol/PatrolIntelligenceSurface.tsx?raw';
|
||||
import aiPatrolSchedulePresentationSource from '@/utils/aiPatrolSchedulePresentation.ts?raw';
|
||||
import patrolSummaryPresentationSource from '@/utils/patrolSummaryPresentation.ts?raw';
|
||||
import aiCostDashboardSource from '@/components/AI/AICostDashboard.tsx?raw';
|
||||
|
|
@ -394,10 +397,17 @@ describe('monitored-system model guardrails', () => {
|
|||
expect(reportingPanelSource).not.toContain("<For each={['24h', '7d', '30d']}>");
|
||||
expect(reportingPresentationSource).toContain('export const REPORTING_RANGE_OPTIONS');
|
||||
expect(reportingPresentationSource).not.toContain('getReportingToggleButtonClass');
|
||||
expect(aiIntelligenceSource).toContain('buildPatrolScheduleOptions');
|
||||
expect(aiIntelligenceSource).toContain('PATROL_NO_ISSUES_LABEL');
|
||||
expect(aiIntelligenceSource).toContain(
|
||||
"import { PatrolIntelligenceSurface } from '@/features/patrol/PatrolIntelligenceSurface';",
|
||||
);
|
||||
expect(aiIntelligenceSource).not.toContain('buildPatrolScheduleOptions');
|
||||
expect(aiIntelligenceSource).not.toContain('PATROL_NO_ISSUES_LABEL');
|
||||
expect(patrolIntelligenceSurfaceSource).toContain('buildPatrolScheduleOptions');
|
||||
expect(patrolIntelligenceSurfaceSource).toContain('PATROL_NO_ISSUES_LABEL');
|
||||
expect(aiIntelligenceSource).not.toContain('No issues found');
|
||||
expect(patrolIntelligenceSurfaceSource).not.toContain('No issues found');
|
||||
expect(aiIntelligenceSource).not.toContain('const SCHEDULE_PRESETS =');
|
||||
expect(patrolIntelligenceSurfaceSource).not.toContain('const SCHEDULE_PRESETS =');
|
||||
expect(aiPatrolSchedulePresentationSource).toContain('export const PATROL_SCHEDULE_PRESETS');
|
||||
expect(aiPatrolSchedulePresentationSource).toContain(
|
||||
'export function buildPatrolScheduleOptions',
|
||||
|
|
@ -524,14 +534,21 @@ describe('monitored-system model guardrails', () => {
|
|||
});
|
||||
|
||||
it('keeps alerts agent thresholds sourced from unified agent resources', () => {
|
||||
expect(alertsPageSource).toContain('const agentResources = createMemo(');
|
||||
expect(alertsPageSource).toContain('agents={agentResources()}');
|
||||
expect(alertsPageSource).toContain("resourceType: 'Agent Disk'");
|
||||
expect(alertsPageSource).not.toContain("resourceType: 'Host Disk'");
|
||||
expect(alertsPageSource).toContain('agentDefaults');
|
||||
expect(alertsPageSource).toContain('disableAllAgents');
|
||||
expect(alertsPageSource).not.toContain('hostDefaults');
|
||||
expect(alertsPageSource).not.toContain('disableAllHosts');
|
||||
expect(alertsPageSource).toContain(
|
||||
"import { AlertsConfigurationSurface } from '@/features/alerts/AlertsConfigurationSurface';",
|
||||
);
|
||||
expect(alertsPageSource).not.toContain('const agentResources = createMemo(');
|
||||
expect(alertsPageSource).not.toContain("resourceType: 'Agent Disk'");
|
||||
expect(alertsConfigurationSurfaceSource).toContain('<ThresholdsTab');
|
||||
expect(thresholdsTableSource).toContain(
|
||||
"import { useThresholdsData } from '@/features/alerts/thresholds/hooks/useThresholdsData';",
|
||||
);
|
||||
expect(thresholdsDataHookSource).toContain("resourceType: 'Agent Disk'");
|
||||
expect(thresholdsDataHookSource).not.toContain("resourceType: 'Host Disk'");
|
||||
expect(thresholdsTableSource).toContain('props.agentDefaults');
|
||||
expect(thresholdsTableSource).toContain('disableAllAgents');
|
||||
expect(thresholdsTableSource).not.toContain('hostDefaults');
|
||||
expect(thresholdsTableSource).not.toContain('disableAllHosts');
|
||||
});
|
||||
|
||||
it('keeps setup and node summary fallbacks aware of v6 agent facets', () => {
|
||||
|
|
@ -602,7 +619,11 @@ describe('monitored-system model guardrails', () => {
|
|||
expect(aiChatSource).not.toContain('const normalizeControlLevel =');
|
||||
expect(aiChatSource).not.toContain('const labelForControlLevel =');
|
||||
expect(aiChatSource).not.toContain('const controlTone =');
|
||||
expect(aiChatSource).toContain(
|
||||
expect(aiChatSource).toContain('const mentionsForAPI =');
|
||||
expect(aiChatSource).toContain('? mentions.map((mention) => ({');
|
||||
expect(aiChatSource).toContain('name: mention.label,');
|
||||
expect(aiChatSource).toContain('type: mention.type,');
|
||||
expect(aiChatSource).not.toContain(
|
||||
'const mentionsForAPI = mentions.length > 0 ? mentions : undefined;',
|
||||
);
|
||||
expect(aiChatPresentationSource).toContain('export const AI_CHAT_SESSION_EMPTY_STATE');
|
||||
|
|
@ -862,10 +883,10 @@ describe('monitored-system model guardrails', () => {
|
|||
"if (path.includes('/thresholds/containers')) return 'docker';",
|
||||
);
|
||||
expect(thresholdsTableSource).toContain('/thresholds/agents');
|
||||
expect(thresholdsTableSource).toContain("resourceType: 'Agent Disk'");
|
||||
expect(thresholdsDataHookSource).toContain("resourceType: 'Agent Disk'");
|
||||
expect(thresholdsTableSource).toContain('getAlertThresholdsSectionTitles');
|
||||
expect(thresholdsTableSource).toContain('title={sectionTitles.agentDisks}');
|
||||
expect(thresholdsTableSource).not.toContain("resourceType: 'Host Disk'");
|
||||
expect(thresholdsDataHookSource).not.toContain("resourceType: 'Host Disk'");
|
||||
expect(thresholdsTableSource).toContain('props.agentDefaults');
|
||||
expect(thresholdsTableSource).not.toContain('props.hostDefaults');
|
||||
expect(thresholdsTableSource).not.toContain('timeThresholds().host');
|
||||
|
|
|
|||
1522
frontend-modern/src/features/patrol/PatrolIntelligenceSurface.tsx
Normal file
1522
frontend-modern/src/features/patrol/PatrolIntelligenceSurface.tsx
Normal file
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -273,6 +273,7 @@ import diagnosticsPanelSource from '@/components/Settings/DiagnosticsPanel.tsx?r
|
|||
import diagnosticsPresentationSource from '@/utils/diagnosticsPresentation.ts?raw';
|
||||
import aiSettingsSource from '@/components/Settings/AISettings.tsx?raw';
|
||||
import aiIntelligenceSource from '@/pages/AIIntelligence.tsx?raw';
|
||||
import patrolIntelligenceSurfaceSource from '@/features/patrol/PatrolIntelligenceSurface.tsx?raw';
|
||||
import aiQuickstartPresentationSource from '@/utils/aiQuickstartPresentation.ts?raw';
|
||||
import aiCostPresentationSource from '@/utils/aiCostPresentation.ts?raw';
|
||||
import thresholdSliderPresentationSource from '@/utils/thresholdSliderPresentation.ts?raw';
|
||||
|
|
@ -2660,21 +2661,26 @@ describe('frontend resource type boundaries', () => {
|
|||
expect(aiSettingsSource).not.toContain(
|
||||
"providerTestResult()?.success ? 'text-green-600' : 'text-red-600'",
|
||||
);
|
||||
expect(aiIntelligenceSource).toContain('getPatrolSummaryPresentation');
|
||||
expect(aiIntelligenceSource).toContain('getAIQuickstartCreditsPresentation');
|
||||
expect(aiIntelligenceSource).not.toContain(
|
||||
expect(aiIntelligenceSource).toContain(
|
||||
"import { PatrolIntelligenceSurface } from '@/features/patrol/PatrolIntelligenceSurface';",
|
||||
);
|
||||
expect(aiIntelligenceSource).not.toContain('getPatrolSummaryPresentation');
|
||||
expect(aiIntelligenceSource).not.toContain('getAIQuickstartCreditsPresentation');
|
||||
expect(patrolIntelligenceSurfaceSource).toContain('getPatrolSummaryPresentation');
|
||||
expect(patrolIntelligenceSurfaceSource).toContain('getAIQuickstartCreditsPresentation');
|
||||
expect(patrolIntelligenceSurfaceSource).not.toContain(
|
||||
"summaryStats().criticalFindings > 0\n ? 'bg-red-50 dark:bg-red-900 border-red-200 dark:border-red-800'",
|
||||
);
|
||||
expect(aiIntelligenceSource).not.toContain(
|
||||
expect(patrolIntelligenceSurfaceSource).not.toContain(
|
||||
"summaryStats().warningFindings > 0\n ? 'bg-amber-50 dark:bg-amber-900 border-amber-200 dark:border-amber-800'",
|
||||
);
|
||||
expect(aiIntelligenceSource).not.toContain(
|
||||
expect(patrolIntelligenceSurfaceSource).not.toContain(
|
||||
"summaryStats().fixedCount > 0\n ? 'bg-green-50 dark:bg-green-900 border-green-200 dark:border-green-800'",
|
||||
);
|
||||
expect(patrolSummaryPresentationSource).toContain(
|
||||
'export function getPatrolSummaryPresentation',
|
||||
);
|
||||
expect(aiIntelligenceSource).not.toContain(
|
||||
expect(patrolIntelligenceSurfaceSource).not.toContain(
|
||||
"(patrolStatus()?.quickstart_credits_remaining ?? 0) > 0\n ? 'bg-blue-50 dark:bg-blue-950 border-blue-200 dark:border-blue-800 text-blue-700 dark:text-blue-300'",
|
||||
);
|
||||
expect(aiQuickstartPresentationSource).toContain(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue