From 6dce36fbabb9478e4d84f25aa36f0a72ef7e49ad Mon Sep 17 00:00:00 2001 From: rcourtman Date: Thu, 25 Jun 2026 14:37:04 +0100 Subject: [PATCH] Clarify Patrol current-work copy --- docs/AI.md | 2 +- ...tention-queue-strong-version-2026-06-25.md | 5 ++++ .../v6/internal/subsystems/ai-runtime.md | 6 ++--- .../v6/internal/subsystems/api-contracts.md | 10 +++---- .../subsystems/frontend-primitives.md | 8 +++--- .../subsystems/patrol-intelligence.md | 8 +++--- .../api/__tests__/agentCapabilities.test.ts | 4 +-- .../Settings/AIModelSelectionSection.tsx | 2 +- .../__tests__/settingsArchitecture.test.ts | 3 +++ .../PatrolIntelligenceHeader.test.ts | 2 +- .../PatrolIntelligenceWorkspace.test.ts | 2 +- .../patrolControlPresentation.test.ts | 26 +++++++++---------- .../patrolInvestigationContextModel.test.ts | 8 +++--- .../patrol/patrolControlPresentation.ts | 26 +++++++++---------- .../pages/__tests__/AIIntelligence.test.tsx | 16 +++++++----- .../frontendResourceTypeBoundaries.test.ts | 2 +- .../patrolEmptyStatePresentation.test.ts | 14 +++++----- .../__tests__/patrolPagePresentation.test.ts | 10 +++---- .../src/utils/patrolEmptyStatePresentation.ts | 13 +++++----- .../src/utils/patrolPagePresentation.ts | 6 ++--- internal/agentcapabilities/manifest.go | 2 +- internal/agentcapabilities/markdown_test.go | 4 +-- internal/api/contract_test.go | 2 +- .../ai_runtime_docs_policy_test.py | 2 +- 24 files changed, 98 insertions(+), 85 deletions(-) diff --git a/docs/AI.md b/docs/AI.md index 637d21cb2..005ef1533 100644 --- a/docs/AI.md +++ b/docs/AI.md @@ -11,7 +11,7 @@ Pulse Intelligence is built around a shared **Pulse Intelligence Core**: Canonic That core is deliberately surfaced with Patrol as the primary built-in operator and Assistant plus MCP as access paths over the same governed capabilities: -1. **Pulse Patrol**: Patrol is the first-party operations surface: it watches, investigates, acts within the chosen Patrol mode, verifies outcomes, and records what happened. +1. **Pulse Patrol**: Patrol is the first-party operations surface: it checks infrastructure, investigates issues, follows the chosen Patrol mode before acting, verifies outcomes, and records what happened. 2. **Pulse Assistant**: The contextual explanation, approval, and handoff surface for Patrol findings, governed actions, verification, and operator questions. Affordances: tools and interactive questions. 3. **Pulse MCP**: The external-agent adapter that projects canonical Pulse Intelligence capabilities as MCP tools. Affordances: tools, resources, prompts, and capability metadata. diff --git a/docs/release-control/v6/internal/records/protection-posture-attention-queue-strong-version-2026-06-25.md b/docs/release-control/v6/internal/records/protection-posture-attention-queue-strong-version-2026-06-25.md index 0be23b391..652158e3b 100644 --- a/docs/release-control/v6/internal/records/protection-posture-attention-queue-strong-version-2026-06-25.md +++ b/docs/release-control/v6/internal/records/protection-posture-attention-queue-strong-version-2026-06-25.md @@ -93,6 +93,11 @@ loop, and routes the operator from real findings/evidence to safe action. command palette, shortcut copy, Patrol page title, and focused tests. Browser proof confirmed authenticated `/` lands on `/proxmox/overview`, while `/patrol` shows the `Patrol` title and heading on desktop and mobile. +- 2026-06-25: Simplified Patrol copy across the page header, mode control, + current-work summary, empty states, Settings model selector, and agent + surface manifest so Patrol consistently reads as the checking loop: check + infrastructure, list current issues, ask according to Patrol mode, verify, + and record the result. ## Evidence diff --git a/docs/release-control/v6/internal/subsystems/ai-runtime.md b/docs/release-control/v6/internal/subsystems/ai-runtime.md index 42a1948ec..d878b67c7 100644 --- a/docs/release-control/v6/internal/subsystems/ai-runtime.md +++ b/docs/release-control/v6/internal/subsystems/ai-runtime.md @@ -21,9 +21,9 @@ Own the Pulse Intelligence Core: canonical context, governed actions, safety gates, approval state, action audit, and verification. That core backs Pulse -Patrol as the primary built-in operator that watches, investigates, acts within -the chosen Patrol mode, verifies outcomes, and records what happened. Pulse -Assistant is the contextual +Patrol as the primary built-in operator that checks infrastructure, investigates +issues, follows the chosen Patrol mode before acting, verifies outcomes, and +records what happened. Pulse Assistant is the contextual explanation, approval, and handoff access path over that same work, while the Pulse MCP adapter is the external-agent access path over canonical API contracts. The subsystem also owns AI orchestration, runtime cost control, diff --git a/docs/release-control/v6/internal/subsystems/api-contracts.md b/docs/release-control/v6/internal/subsystems/api-contracts.md index 1459512cf..8d7983db9 100644 --- a/docs/release-control/v6/internal/subsystems/api-contracts.md +++ b/docs/release-control/v6/internal/subsystems/api-contracts.md @@ -912,8 +912,8 @@ payload shape change when the portal presents compact client rows. `/api/agent/capabilities.mcpAdapter`, not component-local constants. The default setup copy must frame connected agents as optional access to Pulse context and Patrol work, keep Patrol as the built-in operator that - watches, acts within Patrol mode, asks when approval is required, verifies - outcomes, and records history, and say external agents use that same + checks infrastructure, follows Patrol mode before acting, asks when approval + is required, verifies outcomes, and records history, and say external agents use that same boundary. It must not use "Use Pulse MCP only" or "outside client" copy, and it must not describe external-agent setup as a separate operator journey. The Patrol control handoff belongs to the Patrol control route; API Access @@ -1760,9 +1760,9 @@ payload shape change when the portal presents compact client rows. alone and the Patrol status presentation boundary, so trigger/scheduling status from Patrol status APIs stays in the header/control surface instead of being - repeated as default status chrome, watch-only presentation says Patrol watches + repeated as default status chrome, watch-only presentation says Patrol checks infrastructure and shows current issues while the selected Watch only mode - describes the capability positively, such as Patrol watching infrastructure + describes the capability positively, such as Patrol checking infrastructure and reporting issues only, avoiding repeated header/control sentences, `Will not` policy-list wording, secondary Limits disclosures, or repeated infrastructure-unchanged caveats, and the browser-visible label stays @@ -1975,7 +1975,7 @@ payload shape change when the portal presents compact client rows. policy rather than changing the compatibility API boundary; setup-only readiness may hide those run/configuration affordances, but the visible Patrol mode selector remains the primary policy boundary during setup - and the Patrol mode presentation boundary, so `frontend-modern/src/features/patrol/PatrolIntelligenceWorkspace.tsx` routes active Patrol findings into the Patrol-owned findings workflow, renders the first-party loop as watch/investigate/act-under-policy/verify/record, uses `Patrol mode` as the human-facing name for the governed autonomy selector while preserving `patrol_control`, `patrolControl*`, and `patrol_autonomy` only for compatibility route and wire identifiers, and demotes Assistant and external-agent readiness out of the primary operator loop without introducing a new API request shape, frontend-authored tool route, serialized remediation plan, or page-local MCP setup contract; direct single-finding CTAs must derive from existing finding-presentation helpers and canonical routes such as the Patrol provider-settings route, selected findings, approvals, and history rows may still open contextual Assistant handoffs through their governed owners, the user-facing `Patrol` route title and `Open work` queue title must remain presentation labels over the same current-work status contract rather than new payload states, setup-only Patrol runtime failures must use existing finding/runtime fields to render the Patrol-owned `Fix Patrol setup` framing, a dedicated setup task, and one direct `Open Provider & Models` action while suppressing the readiness banner, generic issue-row chips, filter chrome, and run-history action chrome that would compete with provider setup, but recent changes, correlations, and policy-coverage payloads must not render as a generic first-party Details/evidence console on the Patrol page, and raw finding lifecycle telemetry must be reserved for explicit all/resolved/history or selected-run review states instead of default active current-issue expansion + and the Patrol mode presentation boundary, so `frontend-modern/src/features/patrol/PatrolIntelligenceWorkspace.tsx` routes active Patrol findings into the Patrol-owned findings workflow, renders the first-party loop as check/investigate/act-under-policy/verify/record, uses `Patrol mode` as the human-facing name for the governed autonomy selector while preserving `patrol_control`, `patrolControl*`, and `patrol_autonomy` only for compatibility route and wire identifiers, and demotes Assistant and external-agent readiness out of the primary operator loop without introducing a new API request shape, frontend-authored tool route, serialized remediation plan, or page-local MCP setup contract; direct single-finding CTAs must derive from existing finding-presentation helpers and canonical routes such as the Patrol provider-settings route, selected findings, approvals, and history rows may still open contextual Assistant handoffs through their governed owners, the user-facing `Patrol` route title and `Open work` queue title must remain presentation labels over the same current-work status contract rather than new payload states, setup-only Patrol runtime failures must use existing finding/runtime fields to render the Patrol-owned `Fix Patrol setup` framing, a dedicated setup task, and one direct `Open Provider & Models` action while suppressing the readiness banner, generic issue-row chips, filter chrome, and run-history action chrome that would compete with provider setup, but recent changes, correlations, and policy-coverage payloads must not render as a generic first-party Details/evidence console on the Patrol page, and raw finding lifecycle telemetry must be reserved for explicit all/resolved/history or selected-run review states instead of default active current-issue expansion The Patrol page may consume server-authored readiness and preflight-backed status, but it must translate that transport state into `Patrol setup issue` or `Patrol setup warning`, provider/model context, and the canonical diff --git a/docs/release-control/v6/internal/subsystems/frontend-primitives.md b/docs/release-control/v6/internal/subsystems/frontend-primitives.md index 6bfa02f55..e3f49c7a7 100644 --- a/docs/release-control/v6/internal/subsystems/frontend-primitives.md +++ b/docs/release-control/v6/internal/subsystems/frontend-primitives.md @@ -89,7 +89,7 @@ work extends shared components instead of creating new local variants. 59b. `frontend-modern/src/components/shared/FilterBar/useSavedViews.ts` 59c. `frontend-modern/src/components/shared/FilterBar/filterOptionPresentation.tsx` 60. `frontend-modern/src/components/shared/TypeColumn.guardrails.test.ts` -61. `frontend-modern/src/features/` (including Patrol presentation, where Patrol control starter counts are context only even when mirrored through `patrolAutonomy*` compatibility fields, successful direct Patrol control saves may record the content-free `patrol_control` starter only when paid control is available and the effective control posture changes and must then refresh Patrol status, findings, approvals, and run history before the operator waits for polling, legacy `proActivation*` starter aliases must not render a separate proof strip by themselves, Patrol control completed/resolved counts may only project backend-owned terminal proof, current active findings and pending approvals outrank historical completion proof in the primary operator state, selected run history must read as a Patrol run record rather than a findings filter or snapshot workflow, terminal verified/rejected outcomes with no active finding or pending approval must stay history detail without rendering a no-op proof strip, resolved-only issue history must not be promoted into current-work copy or actions, compact recurrence/trust counters must read as historical evidence rather than current issue state, Patrol-owned status/history evidence must keep the assessment visible when the broader intelligence summary is missing, the Patrol route and page title must lead with Patrol while the default workspace underneath may use Open work and run history stays a deliberate secondary review surface, setup-only Patrol runtime failures must instead use `Fix Patrol setup` framing with a dedicated setup task and direct provider-settings action while suppressing generic issue-row chips and filter chrome, Patrol must not expose a generic Details/supporting-context panel for nearby activity, related patterns, or policy limits, locked-control copy must state the watch-only boundary in positive capability language by saying Patrol watches infrastructure and shows current issues, avoid repeating the same sentence across the header and control, and avoid repeatedly restating infrastructure-unchanged caveats or relying on disabled controls, compact Pro badges, Limits controls, or manual-review framing, `patrolControlValueState` decides whether a terminal decision is partial review context or verified value proof while `patrolAutonomyValueState` remains a compatibility mirror, legacy `proActivation*` fields are compatibility fallback only, native Patrol state must not load the operations-loop status projection to decide current work, local Patrol state must expose issue-backed `patrolWork*` evidence rather than legacy proof naming, Patrol mode labels remain domain copy that must describe backend-owned risk policy without creating page-local safety thresholds, the Patrol schedule and model drawer must stay separate from the always-visible Patrol mode selector instead of duplicating the four control choices or reintroducing save/apply configuration framing, and Patrol header refresh controls must call an explicit operator-refresh handler whose spinning/disabled state is separate from background polling and initial data loads) +61. `frontend-modern/src/features/` (including Patrol presentation, where Patrol control starter counts are context only even when mirrored through `patrolAutonomy*` compatibility fields, successful direct Patrol control saves may record the content-free `patrol_control` starter only when paid control is available and the effective control posture changes and must then refresh Patrol status, findings, approvals, and run history before the operator waits for polling, legacy `proActivation*` starter aliases must not render a separate proof strip by themselves, Patrol control completed/resolved counts may only project backend-owned terminal proof, current active findings and pending approvals outrank historical completion proof in the primary operator state, selected run history must read as a Patrol run record rather than a findings filter or snapshot workflow, terminal verified/rejected outcomes with no active finding or pending approval must stay history detail without rendering a no-op proof strip, resolved-only issue history must not be promoted into current-work copy or actions, compact recurrence/trust counters must read as historical evidence rather than current issue state, Patrol-owned status/history evidence must keep the assessment visible when the broader intelligence summary is missing, the Patrol route and page title must lead with Patrol while the default workspace underneath may use Open work and run history stays a deliberate secondary review surface, setup-only Patrol runtime failures must instead use `Fix Patrol setup` framing with a dedicated setup task and direct provider-settings action while suppressing generic issue-row chips and filter chrome, Patrol must not expose a generic Details/supporting-context panel for nearby activity, related patterns, or policy limits, locked-control copy must state the watch-only boundary in positive capability language by saying Patrol checks infrastructure and shows current issues, avoid repeating the same sentence across the header and control, and avoid repeatedly restating infrastructure-unchanged caveats or relying on disabled controls, compact Pro badges, Limits controls, or manual-review framing, `patrolControlValueState` decides whether a terminal decision is partial review context or verified value proof while `patrolAutonomyValueState` remains a compatibility mirror, legacy `proActivation*` fields are compatibility fallback only, native Patrol state must not load the operations-loop status projection to decide current work, local Patrol state must expose issue-backed `patrolWork*` evidence rather than legacy proof naming, Patrol mode labels remain domain copy that must describe backend-owned risk policy without creating page-local safety thresholds, the Patrol schedule and model drawer must stay separate from the always-visible Patrol mode selector instead of duplicating the four control choices or reintroducing save/apply configuration framing, and Patrol header refresh controls must call an explicit operator-refresh handler whose spinning/disabled state is separate from background polling and initial data loads) 62. `frontend-modern/src/components/SetupWizard/SetupWizard.tsx` 63. `frontend-modern/src/components/Settings/useSettingsInfrastructurePanelProps.ts` 64. `frontend-modern/src/components/SetupWizard/SetupCompletionPreview.tsx` @@ -463,9 +463,9 @@ AGENT_SURFACE_ID_PULSE_MCP)` and `getAgentSurfaceToolPosturePresentation`, rather than exporting a Pulse-MCP-specific tool-contract helper. The panel's settings shell may arrange the external-agent setup hierarchy, but it must keep connected agents framed as optional access to Pulse context and Patrol - work, with Patrol as the built-in operator that watches, acts within Patrol - mode, asks when approval is required, verifies outcomes, and records - history, state that external agents use that same boundary, and make the canonical + work, with Patrol as the built-in operator that checks infrastructure, + follows Patrol mode before acting, asks when approval is required, verifies + outcomes, and records history, state that external agents use that same boundary, and make the canonical `/settings/pulse-intelligence/assistant#external-agent-setup` route land on and briefly focus this panel with setup open rather than leaving the user at the generic API token inventory. Legacy `/settings/security/api#external-agent-setup` and diff --git a/docs/release-control/v6/internal/subsystems/patrol-intelligence.md b/docs/release-control/v6/internal/subsystems/patrol-intelligence.md index 008bd188f..2a04b89cf 100644 --- a/docs/release-control/v6/internal/subsystems/patrol-intelligence.md +++ b/docs/release-control/v6/internal/subsystems/patrol-intelligence.md @@ -90,9 +90,9 @@ Patrol-specific presentation helpers. failure: `usePatrolIntelligenceState.ts` must fail soft, keep the Patrol workspace visible, and let `PatrolIntelligenceBanners.tsx` show one short stale-data retry banner without leaking raw transport errors. - Watch-only and locked-control copy must describe Patrol as watching + Watch-only and locked-control copy must describe Patrol as checking infrastructure and showing current issues, while the selected Watch only - mode must describe the capability positively, such as Patrol watching + mode must describe the capability positively, such as Patrol checking infrastructure and reporting issues only. It must not frame the free/monitor boundary as evidence recording, proof collection, or a disabled version of remediation. Paid mode labels @@ -223,7 +223,7 @@ attention`, `approval needed`, `outcome verified`, `no active work`) instead mode, and Open work label visible instead of reintroducing a generic status strip. Plan-locked Patrol mode copy must present the effective Watch only - capability as the current product state: Patrol watches resources, detects + capability as the current product state: Patrol checks resources, detects issues, and records findings. The free Patrol working surface must not render a disabled paid-mode matrix, compact Pro badges, or any paid-mode disclosure; it stays clean of paid-feature surfacing entirely. Runtime-locked Pro installs may still @@ -394,7 +394,7 @@ attention`, `approval needed`, `outcome verified`, `no active work`) instead discovery belongs outside the daily-use Patrol surface. Watch-only copy in `patrolPagePresentation.ts`, `patrolControlPresentation.ts`, and `patrolAutonomyAvailability.ts` must describe Watch only in positive, - capability-first language: Patrol watches infrastructure, records current + capability-first language: Patrol checks infrastructure, records current issues, or records issues as it finds them. They must not repeat the same sentence across the header and mode control, repeatedly restate infrastructure-unchanged caveats in the default view, or imply Patrol's main diff --git a/frontend-modern/src/api/__tests__/agentCapabilities.test.ts b/frontend-modern/src/api/__tests__/agentCapabilities.test.ts index ac4f4f6ec..51308d864 100644 --- a/frontend-modern/src/api/__tests__/agentCapabilities.test.ts +++ b/frontend-modern/src/api/__tests__/agentCapabilities.test.ts @@ -52,7 +52,7 @@ const surfaceContract = { id: 'pulse_patrol', label: 'Pulse Patrol', description: - 'Patrol is the first-party operations surface: it watches, investigates, acts within the chosen Patrol mode, verifies outcomes, and records what happened.', + 'Patrol is the first-party operations surface: it checks infrastructure, investigates issues, follows the chosen Patrol mode before acting, verifies outcomes, and records what happened.', }, operatorSurfaces: [ { @@ -519,7 +519,7 @@ describe('agent capabilities API client', () => { ]); expect(entries.map((entry) => entry.description)).toEqual([ 'Canonical context, governed actions, safety gates, approval state, action audit, and verification.', - 'Patrol is the first-party operations surface: it watches, investigates, acts within the chosen Patrol mode, verifies outcomes, and records what happened.', + 'Patrol is the first-party operations surface: it checks infrastructure, investigates issues, follows the chosen Patrol mode before acting, verifies outcomes, and records what happened.', 'The contextual explanation, approval, and handoff surface for Patrol findings, governed actions, verification, and operator questions.', 'The external-agent adapter.', ]); diff --git a/frontend-modern/src/components/Settings/AIModelSelectionSection.tsx b/frontend-modern/src/components/Settings/AIModelSelectionSection.tsx index e3cfe1943..3998a85e4 100644 --- a/frontend-modern/src/components/Settings/AIModelSelectionSection.tsx +++ b/frontend-modern/src/components/Settings/AIModelSelectionSection.tsx @@ -36,7 +36,7 @@ const MODEL_OVERRIDE_CONFIG: Record< patrol: { formKey: 'patrolModel', label: 'Patrol model', - description: 'Used when Patrol watches, investigates, and verifies work.', + description: 'Used when Patrol checks, investigates, and verifies work.', ariaLabel: 'Patrol model identifier', title: 'Select Patrol model', }, diff --git a/frontend-modern/src/components/Settings/__tests__/settingsArchitecture.test.ts b/frontend-modern/src/components/Settings/__tests__/settingsArchitecture.test.ts index 498f0c1ff..6bbd52cca 100644 --- a/frontend-modern/src/components/Settings/__tests__/settingsArchitecture.test.ts +++ b/frontend-modern/src/components/Settings/__tests__/settingsArchitecture.test.ts @@ -992,6 +992,9 @@ describe('settings architecture guardrails', () => { ); expect(aiModelSelectionSectionSource).not.toContain('approved fix execution'); expect(aiModelSelectionSectionSource).toContain("label: 'Patrol model'"); + expect(aiModelSelectionSectionSource).toContain( + 'Used when Patrol checks, investigates, and verifies work.', + ); expect(aiModelSelectionSectionSource).toContain("label: 'Service context model'"); expect(aiModelSelectionSectionSource).toContain('export const AIModelOverrideField'); expect(aiSettingsSource).toContain( diff --git a/frontend-modern/src/features/patrol/__tests__/PatrolIntelligenceHeader.test.ts b/frontend-modern/src/features/patrol/__tests__/PatrolIntelligenceHeader.test.ts index e0cde9f2a..e9121bfc8 100644 --- a/frontend-modern/src/features/patrol/__tests__/PatrolIntelligenceHeader.test.ts +++ b/frontend-modern/src/features/patrol/__tests__/PatrolIntelligenceHeader.test.ts @@ -95,7 +95,7 @@ describe('PatrolIntelligenceHeader', () => { expect(PATROL_AUTONOMY_POLICY_PRESENTATION).toEqual({ monitor: { label: 'Watch only', - detail: 'Patrol reports issues without making changes.', + detail: 'Patrol checks and reports issues without making changes.', compactLabel: 'Watch only', }, approval: { diff --git a/frontend-modern/src/features/patrol/__tests__/PatrolIntelligenceWorkspace.test.ts b/frontend-modern/src/features/patrol/__tests__/PatrolIntelligenceWorkspace.test.ts index 133daf87d..56f643bf0 100644 --- a/frontend-modern/src/features/patrol/__tests__/PatrolIntelligenceWorkspace.test.ts +++ b/frontend-modern/src/features/patrol/__tests__/PatrolIntelligenceWorkspace.test.ts @@ -74,6 +74,6 @@ describe('PatrolIntelligenceWorkspace trust strip', () => { expect(workspaceSource).toContain('!state.selectedRun()'); expect(PATROL_WORKSPACE_RUN_RECORD_TITLE).toBe('Check details'); expect(PATROL_WORKSPACE_RUN_RECORD_DESCRIPTION).toBe('What Patrol found during this run.'); - expect(PATROL_WORKSPACE_HISTORY_DESCRIPTION).toBe('Past Patrol checks.'); + expect(PATROL_WORKSPACE_HISTORY_DESCRIPTION).toBe('Past checks and what Patrol recorded.'); }); }); diff --git a/frontend-modern/src/features/patrol/__tests__/patrolControlPresentation.test.ts b/frontend-modern/src/features/patrol/__tests__/patrolControlPresentation.test.ts index 7815c67a1..525fd7f9e 100644 --- a/frontend-modern/src/features/patrol/__tests__/patrolControlPresentation.test.ts +++ b/frontend-modern/src/features/patrol/__tests__/patrolControlPresentation.test.ts @@ -16,7 +16,7 @@ describe('patrolControlPresentation', () => { expect(PATROL_AUTONOMY_POLICY_PRESENTATION).toEqual({ monitor: { label: 'Watch only', - detail: 'Patrol reports issues without making changes.', + detail: 'Patrol checks and reports issues without making changes.', compactLabel: 'Watch only', }, approval: { @@ -41,23 +41,23 @@ describe('patrolControlPresentation', () => { it.each([ [ 'monitor', - 'Patrol is ready to check infrastructure and show issues.', - 'Issues Patrol finds that need you appear here.', + 'Patrol is ready to check infrastructure and list current issues.', + 'Patrol lists current issues here after each check.', ], [ 'approval', - 'Patrol is ready to watch and investigate. You approve every change.', - 'Investigations and approval requests that need you appear here.', + 'Patrol is ready to check, investigate, and ask before any change.', + 'Patrol lists investigations and approval requests here.', ], [ 'assisted', - 'Patrol is ready to watch, investigate, and handle safe fixes when policy allows it.', - 'Issues Patrol is handling appear here. Approval requests appear when needed.', + 'Patrol is ready to check, investigate, and fix safe issues when policy allows it.', + 'Patrol lists issues it is handling here and asks when approval is needed.', ], [ 'full', - 'Patrol is ready to watch, investigate, and act automatically within your policy.', - 'Issues Patrol is handling appear here. Approval requests appear when policy requires them.', + 'Patrol is ready to check, investigate, and act automatically within your policy.', + 'Patrol lists issues it is handling here and asks when policy requires approval.', ], ] satisfies Array<[PatrolAutonomyLevel, string, string]>)( 'describes %s mode without generic control-level wording', @@ -70,14 +70,14 @@ describe('patrolControlPresentation', () => { it('does not advertise investigation or fixes while Patrol mode is locked', () => { expect(getPatrolReadyWorkDetail({ autonomyLevel: 'full', autonomyLocked: true })).toBe( - 'Patrol is ready to check infrastructure and show issues.', + 'Patrol is ready to check infrastructure and list current issues.', ); expect( getPatrolQueueWorkspaceDescription({ autonomyLevel: 'full', autonomyLocked: true, }), - ).toBe('Issues Patrol finds that need you appear here.'); + ).toBe('Patrol lists current issues here after each check.'); }); it('summarizes the open queue by affected resource instead of raw findings', () => { @@ -98,14 +98,14 @@ describe('patrolControlPresentation', () => { findingCount: 2, affectedResourceCount: 1, }), - ).toBe('2 issues on 1 affected resource.'); + ).toBe('Patrol found 2 issues on 1 affected resource.'); expect( getPatrolQueueWorkspaceDescription({ autonomyLevel: 'approval', findingCount: 1, affectedResourceCount: 1, }), - ).toBe('1 issue on 1 affected resource.'); + ).toBe('Patrol found 1 issue on 1 affected resource.'); }); it('keeps setup-only issue reasons short and actionable', () => { diff --git a/frontend-modern/src/features/patrol/__tests__/patrolInvestigationContextModel.test.ts b/frontend-modern/src/features/patrol/__tests__/patrolInvestigationContextModel.test.ts index 8f7cf613e..fff7bfc58 100644 --- a/frontend-modern/src/features/patrol/__tests__/patrolInvestigationContextModel.test.ts +++ b/frontend-modern/src/features/patrol/__tests__/patrolInvestigationContextModel.test.ts @@ -1493,9 +1493,9 @@ describe('Patrol page header IA framing', () => { const { getPatrolPageHeaderMeta, PATROL_PAGE_DESCRIPTION, PATROL_PAGE_TITLE_TOOLTIP } = await import('@/utils/patrolPagePresentation'); expect(PATROL_PAGE_DESCRIPTION).toBe( - 'Patrol watches, investigates, acts within your chosen mode, verifies outcomes, and records what happened.', + 'Patrol checks your infrastructure, explains what it found, follows your mode before acting, and records the result.', ); - expect(PATROL_PAGE_DESCRIPTION).toContain('acts within your chosen mode'); + expect(PATROL_PAGE_DESCRIPTION).toContain('follows your mode before acting'); expect(PATROL_PAGE_TITLE_TOOLTIP).toBe(PATROL_PAGE_DESCRIPTION); expect(getPatrolPageHeaderMeta()).toMatchObject({ title: 'Patrol', @@ -1504,8 +1504,8 @@ describe('Patrol page header IA framing', () => { }); expect(getPatrolPageHeaderMeta({ autonomyLocked: true })).toMatchObject({ title: 'Patrol', - description: 'Patrol watches infrastructure and shows current issues.', - titleTooltip: 'Patrol watches infrastructure and shows current issues.', + description: 'Patrol checks your infrastructure and shows current issues.', + titleTooltip: 'Patrol checks your infrastructure and shows current issues.', }); }); }); diff --git a/frontend-modern/src/features/patrol/patrolControlPresentation.ts b/frontend-modern/src/features/patrol/patrolControlPresentation.ts index ca83b4cd0..f8a4ee8ee 100644 --- a/frontend-modern/src/features/patrol/patrolControlPresentation.ts +++ b/frontend-modern/src/features/patrol/patrolControlPresentation.ts @@ -8,7 +8,7 @@ export const PATROL_AUTONOMY_POLICY_PRESENTATION: Record< > = { monitor: { label: 'Watch only', - detail: 'Patrol reports issues without making changes.', + detail: 'Patrol checks and reports issues without making changes.', compactLabel: 'Watch only', }, approval: { @@ -29,7 +29,7 @@ export const PATROL_AUTONOMY_POLICY_PRESENTATION: Record< }, }; -export const PATROL_WORKSPACE_HISTORY_DESCRIPTION = 'Past Patrol checks.'; +export const PATROL_WORKSPACE_HISTORY_DESCRIPTION = 'Past checks and what Patrol recorded.'; export const PATROL_WORKSPACE_RUN_RECORD_DESCRIPTION = 'What Patrol found during this run.'; @@ -98,19 +98,19 @@ export function getPatrolSetupIssueReason(input: PatrolSetupIssueReasonInput): s export function getPatrolReadyWorkDetail(input: PatrolControlCopyInput): string { if (input.autonomyLocked) { - return 'Patrol is ready to check infrastructure and show issues.'; + return 'Patrol is ready to check infrastructure and list current issues.'; } switch (input.autonomyLevel) { case 'approval': - return 'Patrol is ready to watch and investigate. You approve every change.'; + return 'Patrol is ready to check, investigate, and ask before any change.'; case 'assisted': - return 'Patrol is ready to watch, investigate, and handle safe fixes when policy allows it.'; + return 'Patrol is ready to check, investigate, and fix safe issues when policy allows it.'; case 'full': - return 'Patrol is ready to watch, investigate, and act automatically within your policy.'; + return 'Patrol is ready to check, investigate, and act automatically within your policy.'; case 'monitor': default: - return 'Patrol is ready to check infrastructure and show issues.'; + return 'Patrol is ready to check infrastructure and list current issues.'; } } @@ -128,26 +128,26 @@ export function getPatrolQueueWorkspaceDescription( const findingCount = normalizeCount(input.findingCount); const affectedResourceCount = normalizeCount(input.affectedResourceCount); if (findingCount > 0 && affectedResourceCount > 0) { - return `${getPatrolFindingIssueCountLabel(findingCount)} on ${formatCount( + return `Patrol found ${getPatrolFindingIssueCountLabel(findingCount)} on ${formatCount( affectedResourceCount, 'affected resource', )}.`; } if (input.autonomyLocked) { - return 'Issues Patrol finds that need you appear here.'; + return 'Patrol lists current issues here after each check.'; } switch (input.autonomyLevel) { case 'approval': - return 'Investigations and approval requests that need you appear here.'; + return 'Patrol lists investigations and approval requests here.'; case 'assisted': - return 'Issues Patrol is handling appear here. Approval requests appear when needed.'; + return 'Patrol lists issues it is handling here and asks when approval is needed.'; case 'full': - return 'Issues Patrol is handling appear here. Approval requests appear when policy requires them.'; + return 'Patrol lists issues it is handling here and asks when policy requires approval.'; case 'monitor': default: - return 'Issues Patrol finds that need you appear here.'; + return 'Patrol lists current issues here after each check.'; } } diff --git a/frontend-modern/src/pages/__tests__/AIIntelligence.test.tsx b/frontend-modern/src/pages/__tests__/AIIntelligence.test.tsx index bb5c60df3..29e82cba2 100644 --- a/frontend-modern/src/pages/__tests__/AIIntelligence.test.tsx +++ b/frontend-modern/src/pages/__tests__/AIIntelligence.test.tsx @@ -635,11 +635,11 @@ describe('AIIntelligence entitlement gating', () => { }); expect( - screen.getByText('Patrol watches infrastructure and shows current issues.'), + screen.getByText('Patrol checks your infrastructure and shows current issues.'), ).toBeInTheDocument(); expect( screen.queryByText( - 'Patrol watches, investigates, acts within the mode you choose, verifies outcomes, and records what happened.', + 'Patrol checks your infrastructure, explains what it found, follows your mode before acting, and records the result.', ), ).not.toBeInTheDocument(); const patrolControlAnchor = document.getElementById(PATROL_CONTROL_ANCHOR); @@ -650,7 +650,7 @@ describe('AIIntelligence entitlement gating', () => { expect(patrolControl.getByText('Patrol mode')).toBeInTheDocument(); expect(patrolControl.getAllByText('Watch only').length).toBeGreaterThan(0); expect( - patrolControl.getByText('Patrol reports issues without making changes.'), + patrolControl.getByText('Patrol checks and reports issues without making changes.'), ).toBeInTheDocument(); expect(patrolControl.queryByRole('button', { name: 'Limits' })).not.toBeInTheDocument(); expect(patrolControl.queryByRole('button', { name: 'Ask first' })).toBeNull(); @@ -671,7 +671,9 @@ describe('AIIntelligence entitlement gating', () => { expect(screen.queryByRole('link', { name: 'View plans' })).not.toBeInTheDocument(); expect(operationsLoopAnchor?.parentElement).toBe(patrolControlAnchor); expect(screen.queryByTestId('patrol-current-work')).not.toBeInTheDocument(); - expect(screen.getByText('Issues Patrol finds that need you appear here.')).toBeInTheDocument(); + expect( + screen.getByText('Patrol lists current issues here after each check.'), + ).toBeInTheDocument(); expect( screen.queryByText('Issues Patrol found. Infrastructure stays unchanged.'), ).not.toBeInTheDocument(); @@ -1195,7 +1197,9 @@ describe('AIIntelligence entitlement gating', () => { expect(screen.getByRole('button', { name: 'Ask first' })).not.toBeDisabled(); expect(screen.getByRole('button', { name: 'Safe auto-fix' })).not.toBeDisabled(); expect(screen.getByRole('button', { name: 'Autopilot' })).not.toBeDisabled(); - expect(screen.getByText('Patrol reports issues without making changes.')).toBeInTheDocument(); + expect( + screen.getByText('Patrol checks and reports issues without making changes.'), + ).toBeInTheDocument(); expect(screen.queryByText('Patrol handles')).not.toBeInTheDocument(); expect(screen.queryByRole('button', { name: 'Limits' })).not.toBeInTheDocument(); expect(screen.queryByText('Hard limits')).not.toBeInTheDocument(); @@ -1876,7 +1880,7 @@ describe('AIIntelligence entitlement gating', () => { expect(patrolControl.getByText('Patrol mode')).toBeInTheDocument(); expect(patrolControl.getAllByText('Watch only').length).toBeGreaterThan(0); expect( - patrolControl.getByText('Patrol reports issues without making changes.'), + patrolControl.getByText('Patrol checks and reports issues without making changes.'), ).toBeInTheDocument(); expect(patrolControl.getByRole('button', { name: 'Ask first' })).not.toBeDisabled(); expect(patrolControl.getByRole('button', { name: 'Safe auto-fix' })).not.toBeDisabled(); diff --git a/frontend-modern/src/utils/__tests__/frontendResourceTypeBoundaries.test.ts b/frontend-modern/src/utils/__tests__/frontendResourceTypeBoundaries.test.ts index 99084071e..29c6415fe 100644 --- a/frontend-modern/src/utils/__tests__/frontendResourceTypeBoundaries.test.ts +++ b/frontend-modern/src/utils/__tests__/frontendResourceTypeBoundaries.test.ts @@ -3689,7 +3689,7 @@ describe('frontend resource type boundaries', () => { expect(runHistoryPanelSource).toContain('getRunHistoryEmptyState'); expect(runHistoryPanelSource).toContain('getRunHistoryLoadingState'); expect(runHistoryPanelSource).not.toContain( - 'No patrol runs yet. Trigger a run to populate history.', + 'No Patrol checks yet. Run Patrol to start history.', ); expect(runHistoryPanelSource).not.toContain('Loading run history…'); expect(runToolCallTraceSource).toContain('getToolCallsLoadingState'); diff --git a/frontend-modern/src/utils/__tests__/patrolEmptyStatePresentation.test.ts b/frontend-modern/src/utils/__tests__/patrolEmptyStatePresentation.test.ts index 21ad1cf9a..92a4c12cb 100644 --- a/frontend-modern/src/utils/__tests__/patrolEmptyStatePresentation.test.ts +++ b/frontend-modern/src/utils/__tests__/patrolEmptyStatePresentation.test.ts @@ -23,7 +23,7 @@ describe('patrolEmptyStatePresentation', () => { it('returns the patrol run history empty state', () => { expect(getRunHistoryEmptyState()).toEqual({ - text: 'No patrol runs yet. Trigger a run to populate history.', + text: 'No Patrol checks yet. Run Patrol to start history.', }); expect(runHistoryPanelSource).toContain('@/components/shared/EmptyState'); expect(runHistoryPanelSource).toContain('variant="panel"'); @@ -70,7 +70,7 @@ describe('patrolEmptyStatePresentation', () => { }), ).toEqual({ title: 'Check needed', - body: 'Run Patrol to check everything and update open issues.', + body: 'Run Patrol to check everything and refresh open work.', tone: 'warning', }); }); @@ -94,7 +94,7 @@ describe('patrolEmptyStatePresentation', () => { }), ).toEqual({ title: 'Check needed', - body: 'Run Patrol to check everything and update open issues.', + body: 'Run Patrol to check everything and refresh open work.', tone: 'warning', }); }); @@ -121,7 +121,7 @@ describe('patrolEmptyStatePresentation', () => { }), ).toEqual({ title: 'Patrol needs review', - body: 'No active findings are listed, but Patrol health is degraded.', + body: 'No current issues are listed, but Patrol health needs review.', tone: 'error', }); }); @@ -156,7 +156,7 @@ describe('patrolEmptyStatePresentation', () => { }), ).toEqual({ title: 'Patrol is checking now', - body: 'The current run will add work here if Patrol finds issues or needs approval.', + body: 'If Patrol finds an issue or needs approval, it will add it here.', tone: 'info', }); }); @@ -176,7 +176,7 @@ describe('patrolEmptyStatePresentation', () => { }), ).toEqual({ title: 'No current issues', - body: 'Run Patrol any time to check again.', + body: 'No action needed from the latest Patrol check. Run Patrol any time to check again.', tone: 'success', }); }); @@ -197,7 +197,7 @@ describe('patrolEmptyStatePresentation', () => { }), ).toEqual({ title: 'No current issues', - body: 'Past issues are in History.', + body: 'Past issues are in History if you need the record.', tone: 'info', }); }); diff --git a/frontend-modern/src/utils/__tests__/patrolPagePresentation.test.ts b/frontend-modern/src/utils/__tests__/patrolPagePresentation.test.ts index f5eb6650e..e69e20ad0 100644 --- a/frontend-modern/src/utils/__tests__/patrolPagePresentation.test.ts +++ b/frontend-modern/src/utils/__tests__/patrolPagePresentation.test.ts @@ -15,24 +15,24 @@ describe('patrolPagePresentation', () => { // users learn the full operations-loop model. expect(PATROL_PAGE_TITLE).toBe('Patrol'); expect(PATROL_PAGE_DESCRIPTION).toBe( - 'Patrol watches, investigates, acts within your chosen mode, verifies outcomes, and records what happened.', + 'Patrol checks your infrastructure, explains what it found, follows your mode before acting, and records the result.', ); expect(PATROL_PAGE_TITLE_TOOLTIP).toBe(PATROL_PAGE_DESCRIPTION); expect(getPatrolPageHeaderMeta()).toEqual({ title: 'Patrol', description: - 'Patrol watches, investigates, acts within your chosen mode, verifies outcomes, and records what happened.', + 'Patrol checks your infrastructure, explains what it found, follows your mode before acting, and records the result.', titleTooltip: - 'Patrol watches, investigates, acts within your chosen mode, verifies outcomes, and records what happened.', + 'Patrol checks your infrastructure, explains what it found, follows your mode before acting, and records the result.', }); }); it('separates locked watch-only capability from Pro Watch only mode', () => { expect(PATROL_PAGE_WATCH_ONLY_DESCRIPTION).toBe( - 'Patrol watches infrastructure and shows current issues.', + 'Patrol checks your infrastructure and shows current issues.', ); expect(PATROL_PAGE_MONITOR_DESCRIPTION).toBe( - 'Watch only: Patrol reports issues without making changes.', + 'Watch only: Patrol checks and reports issues without making changes.', ); expect(getPatrolPageHeaderMeta({ autonomyLocked: true })).toEqual({ title: 'Patrol', diff --git a/frontend-modern/src/utils/patrolEmptyStatePresentation.ts b/frontend-modern/src/utils/patrolEmptyStatePresentation.ts index 59af8ae84..e0f2d34e8 100644 --- a/frontend-modern/src/utils/patrolEmptyStatePresentation.ts +++ b/frontend-modern/src/utils/patrolEmptyStatePresentation.ts @@ -30,7 +30,7 @@ export function getInvestigationMessagesState(loading: boolean, hasMessages: boo export function getRunHistoryEmptyState() { return { - text: 'No patrol runs yet. Trigger a run to populate history.', + text: 'No Patrol checks yet. Run Patrol to start history.', } as const; } @@ -71,18 +71,19 @@ type PatrolRunSnapshotEmptyStateArgs = Pick< | 'error_count' >; -const HEALTHY_PATROL_EMPTY_STATE_BODY = 'Run Patrol any time to check again.'; +const HEALTHY_PATROL_EMPTY_STATE_BODY = + 'No action needed from the latest Patrol check. Run Patrol any time to check again.'; const DEGRADED_COVERAGE_EMPTY_STATE_BODY = - 'Run Patrol to check everything and update open issues.'; + 'Run Patrol to check everything and refresh open work.'; const DEGRADED_HEALTH_EMPTY_STATE_BODY = - 'No active findings are listed, but Patrol health is degraded.'; -const HISTORICAL_REGRESSION_EMPTY_STATE_BODY = 'Past issues are in History.'; + 'No current issues are listed, but Patrol health needs review.'; +const HISTORICAL_REGRESSION_EMPTY_STATE_BODY = 'Past issues are in History if you need the record.'; const PATROL_QUEUE_CLEAR_TITLE = 'No current issues'; const PATROL_QUEUE_RECHECK_TITLE = 'Check needed'; const PATROL_QUEUE_REVIEW_TITLE = 'Patrol needs review'; const PATROL_QUEUE_RUNNING_TITLE = 'Patrol is checking now'; const PATROL_QUEUE_RUNNING_BODY = - 'The current run will add work here if Patrol finds issues or needs approval.'; + 'If Patrol finds an issue or needs approval, it will add it here.'; function getHealthDegradedTone(overallHealth: IntelligenceHealthScore): SemanticTone { return overallHealth.grade === 'D' || overallHealth.grade === 'F' ? 'error' : 'warning'; diff --git a/frontend-modern/src/utils/patrolPagePresentation.ts b/frontend-modern/src/utils/patrolPagePresentation.ts index 1152e7e80..0911ef10c 100644 --- a/frontend-modern/src/utils/patrolPagePresentation.ts +++ b/frontend-modern/src/utils/patrolPagePresentation.ts @@ -3,13 +3,13 @@ import type { PatrolAutonomyLevel } from '@/api/patrol'; export const PATROL_PAGE_TITLE = 'Patrol'; export const PATROL_PAGE_WATCH_ONLY_DESCRIPTION = - 'Patrol watches infrastructure and shows current issues.'; + 'Patrol checks your infrastructure and shows current issues.'; export const PATROL_PAGE_MONITOR_DESCRIPTION = - 'Watch only: Patrol reports issues without making changes.'; + 'Watch only: Patrol checks and reports issues without making changes.'; export const PATROL_PAGE_DESCRIPTION = - 'Patrol watches, investigates, acts within your chosen mode, verifies outcomes, and records what happened.'; + 'Patrol checks your infrastructure, explains what it found, follows your mode before acting, and records the result.'; export const PATROL_PAGE_TITLE_TOOLTIP = PATROL_PAGE_DESCRIPTION; export interface PatrolPageHeaderMetaInput { diff --git a/internal/agentcapabilities/manifest.go b/internal/agentcapabilities/manifest.go index 2bd90e492..62155f031 100644 --- a/internal/agentcapabilities/manifest.go +++ b/internal/agentcapabilities/manifest.go @@ -617,7 +617,7 @@ var canonicalManifest = Manifest{ ProactiveEngine: SurfaceContractComponent{ ID: "pulse_patrol", Label: "Pulse Patrol", - Description: "Patrol is the first-party operations surface: it watches, investigates, acts within the chosen Patrol mode, verifies outcomes, and records what happened.", + Description: "Patrol is the first-party operations surface: it checks infrastructure, investigates issues, follows the chosen Patrol mode before acting, verifies outcomes, and records what happened.", }, OperatorSurfaces: []OperatorSurfaceContract{ { diff --git a/internal/agentcapabilities/markdown_test.go b/internal/agentcapabilities/markdown_test.go index 7669ec208..c29226e59 100644 --- a/internal/agentcapabilities/markdown_test.go +++ b/internal/agentcapabilities/markdown_test.go @@ -92,7 +92,7 @@ func TestPulseIntelligenceOverviewMarkdownProjectsManifestSurfaceContract(t *tes for _, expected := range []string{ "shared **Pulse Intelligence Core**: Canonical context, governed actions, safety gates, approval state, action audit, and verification shared by Pulse Assistant, Pulse MCP, and Pulse Patrol.", "Patrol as the primary built-in operator and Assistant plus MCP as access paths", - "1. **Pulse Patrol**: Patrol is the first-party operations surface: it watches, investigates, acts within the chosen Patrol mode, verifies outcomes, and records what happened.", + "1. **Pulse Patrol**: Patrol is the first-party operations surface: it checks infrastructure, investigates issues, follows the chosen Patrol mode before acting, verifies outcomes, and records what happened.", "2. **Pulse Assistant**: The contextual explanation, approval, and handoff surface for Patrol findings, governed actions, verification, and operator questions. Affordances: tools and interactive questions.", "3. **Pulse MCP**: The external-agent adapter that projects canonical Pulse Intelligence capabilities as MCP tools. Affordances: tools, resources, prompts, and capability metadata.", } { @@ -121,7 +121,7 @@ func TestMCPSurfaceContractMarkdownProjectsManifestSurfaceContract(t *testing.T) for _, expected := range []string{ "**Pulse Intelligence Core**: Canonical context, governed actions, safety gates, approval state, action audit, and verification shared by Pulse Assistant, Pulse MCP, and Pulse Patrol.", - "**Pulse Patrol**: Patrol is the first-party operations surface: it watches, investigates, acts within the chosen Patrol mode, verifies outcomes, and records what happened.", + "**Pulse Patrol**: Patrol is the first-party operations surface: it checks infrastructure, investigates issues, follows the chosen Patrol mode before acting, verifies outcomes, and records what happened.", "**Pulse Assistant** (the native Pulse surface): The contextual explanation, approval, and handoff surface for Patrol findings, governed actions, verification, and operator questions. Affordances: tools and interactive questions.", "**Pulse MCP**: The external-agent adapter that projects canonical Pulse Intelligence capabilities as MCP tools. Affordances: tools, resources, prompts, and capability metadata.", } { diff --git a/internal/api/contract_test.go b/internal/api/contract_test.go index 53f7e92f3..768cfc0e6 100644 --- a/internal/api/contract_test.go +++ b/internal/api/contract_test.go @@ -15883,7 +15883,7 @@ func TestContract_PulseIntelligenceOverviewPinsPatrolPrimaryCore(t *testing.T) { "Canonical context, governed actions, safety gates, approval state, action audit, and verification", "Patrol as the primary built-in operator", "Assistant plus MCP as access paths", - "Patrol is the first-party operations surface: it watches, investigates, acts within the chosen Patrol mode, verifies outcomes, and records what happened", + "Patrol is the first-party operations surface: it checks infrastructure, investigates issues, follows the chosen Patrol mode before acting, verifies outcomes, and records what happened", "Pulse Assistant", "Pulse MCP", "contextual explanation, approval, and handoff surface for Patrol findings", diff --git a/scripts/release_control/ai_runtime_docs_policy_test.py b/scripts/release_control/ai_runtime_docs_policy_test.py index 2136097e0..12fab31df 100644 --- a/scripts/release_control/ai_runtime_docs_policy_test.py +++ b/scripts/release_control/ai_runtime_docs_policy_test.py @@ -42,7 +42,7 @@ class AIRuntimeDocsPolicyTest(unittest.TestCase): ) self.assertIn("Patrol as the primary built-in operator", normalized_content) self.assertIn( - "Pulse Patrol**: Patrol is the first-party operations surface: it watches, investigates, acts within the chosen Patrol mode, verifies outcomes, and records what happened.", + "Pulse Patrol**: Patrol is the first-party operations surface: it checks infrastructure, investigates issues, follows the chosen Patrol mode before acting, verifies outcomes, and records what happened.", normalized_content, ) self.assertIn(