mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-07-10 00:14:38 +00:00
Clarify Patrol current-work copy
This commit is contained in:
parent
056cd59405
commit
6dce36fbab
24 changed files with 98 additions and 85 deletions
|
|
@ -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.
|
||||
<!-- pulse-intelligence-overview:end -->
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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.',
|
||||
]);
|
||||
|
|
|
|||
|
|
@ -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',
|
||||
},
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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: {
|
||||
|
|
|
|||
|
|
@ -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.');
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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', () => {
|
||||
|
|
|
|||
|
|
@ -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.',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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.';
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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');
|
||||
|
|
|
|||
|
|
@ -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',
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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',
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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{
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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.",
|
||||
} {
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue