diff --git a/docs/release-control/v6/internal/subsystems/api-contracts.md b/docs/release-control/v6/internal/subsystems/api-contracts.md index 14fda840b..23c711043 100644 --- a/docs/release-control/v6/internal/subsystems/api-contracts.md +++ b/docs/release-control/v6/internal/subsystems/api-contracts.md @@ -966,6 +966,14 @@ the canonical monitored-system blocked payload. persisted findings created by older binaries must adopt the freshly-classified impact text on next re-detection rather than preserving the empty value. + The Patrol Assistant handoff carries an optional + `intent` field of type `PatrolAssistantFindingIntent` + (`'discuss' | 'explain'`) so contextual entry points on the finding + surface can route through the same handoff builder while seeding + different leading sentences. The structured handoff context + (investigation record, operational memory, pending approval, + proposed fix, next-step action) must be attached identically across + intents; only the seed prompt's framing varies. `unified.UnifiedFinding` also carries a `previous_resolved_fix_summary` operational-memory field captured at regression time from diff --git a/docs/release-control/v6/internal/subsystems/frontend-primitives.md b/docs/release-control/v6/internal/subsystems/frontend-primitives.md index 42a6d243f..b7462e054 100644 --- a/docs/release-control/v6/internal/subsystems/frontend-primitives.md +++ b/docs/release-control/v6/internal/subsystems/frontend-primitives.md @@ -942,9 +942,13 @@ prompt explain the same operator-facing priority. investigation-record framing must derive that prompt copy through `frontend-modern/src/features/patrol/patrolInvestigationContextModel.ts` so shared drawer primitives stay shell-owned rather than becoming a - Patrol-specific prompt formatter. That feature-owned presentation - helper is the single emitter for investigation-record `impact` and - `rollback` fields: when an investigation record exists but those fields + Patrol-specific prompt formatter. The Patrol-owned helper exposes a + `PatrolAssistantFindingIntent` parameter ('discuss' | 'explain') so + contextual entry points can vary the seeded leading sentence without + duplicating the structured-context attachment; shared drawer + primitives must not branch on intent themselves. That feature-owned + presentation helper is the single emitter for investigation-record + `impact` and `rollback` fields: when an investigation record exists but those fields are empty, the helper emits explicit `Impact not assessed` and `Rollback not specified` lines into the model-only Patrol finding prompt context so the operator-visible gap is surfaced to Assistant diff --git a/docs/release-control/v6/internal/subsystems/patrol-intelligence.md b/docs/release-control/v6/internal/subsystems/patrol-intelligence.md index 5f7cd341d..f17d42947 100644 --- a/docs/release-control/v6/internal/subsystems/patrol-intelligence.md +++ b/docs/release-control/v6/internal/subsystems/patrol-intelligence.md @@ -258,7 +258,17 @@ Patrol-specific presentation helpers. renders an `Impact:` line between `Description` and `Recommendation`. The same panel also surfaces `investigation_record.confidence` as a badge in the collapsed finding row (next to the investigation outcome - badge) so operators can scan trust without expanding every card. The + badge) so operators can scan trust without expanding every card. + Findings carry contextual Assistant entry points keyed on intent: the + default "Discuss with Assistant" button opens an open-ended chat + handoff, and a parallel "Explain" button opens the same handoff with + a `PatrolAssistantFindingIntent='explain'` seed that asks the LLM to + walk through what we know, why it matters, how confident the + analysis is, and whether the recommended action is appropriate. Both + buttons must route through `buildPatrolAssistantFindingHandoff` so + the structured context (investigation record, operational memory, + pending approval, proposed fix, next-step action) is attached + uniformly; only the leading sentence differs by intent. The badge palette is provided by `getInvestigationConfidenceBadgeClasses` in `frontend-modern/src/utils/aiFindingPresentation.ts`: high is reassuringly emphasized, medium is neutral, low is a soft amber. diff --git a/frontend-modern/src/components/AI/FindingsPanel.tsx b/frontend-modern/src/components/AI/FindingsPanel.tsx index b2e9aec0f..89ca307f5 100644 --- a/frontend-modern/src/components/AI/FindingsPanel.tsx +++ b/frontend-modern/src/components/AI/FindingsPanel.tsx @@ -498,8 +498,10 @@ export const FindingsPanel: Component = (props) => { } }; - const handleDiscussWithAssistant = async (finding: UnifiedFinding, e: Event) => { - e.stopPropagation(); + const openFindingInAssistant = async ( + finding: UnifiedFinding, + intent: 'discuss' | 'explain', + ) => { await aiIntelligenceStore.loadPendingApprovals(); const subject = getFindingSubjectPresentation(finding).label; const title = getFindingTitlePresentation(finding).label; @@ -537,10 +539,21 @@ export const FindingsPanel: Component = (props) => { proposedFix, investigationRecord: finding.investigationRecord, nextStepAction, + intent, }); aiChatStore.openWithPrompt(handoff.prompt, handoff.context); }; + const handleDiscussWithAssistant = async (finding: UnifiedFinding, e: Event) => { + e.stopPropagation(); + await openFindingInAssistant(finding, 'discuss'); + }; + + const handleExplainFinding = async (finding: UnifiedFinding, e: Event) => { + e.stopPropagation(); + await openFindingInAssistant(finding, 'explain'); + }; + const handleOpenPlanInAssistant = (finding: UnifiedFinding, plan: RemediationPlan, e: Event) => { e.stopPropagation(); const subject = getFindingSubjectPresentation(finding).label; @@ -1022,6 +1035,22 @@ export const FindingsPanel: Component = (props) => { Add Note +