mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-07-10 00:14:38 +00:00
Restore Patrol as operator surface
This commit is contained in:
parent
ad01d77ffa
commit
056cd59405
17 changed files with 148 additions and 144 deletions
|
|
@ -76,19 +76,19 @@ This file must not contain:
|
|||
9. `docs/release-control/v6/internal/subsystems/registry.schema.json`
|
||||
Machine-readable contract for the subsystem registry shape.
|
||||
10. `docs/release-control/v6/internal/subsystems/*.md`
|
||||
Per-subsystem contracts: truth, extension points, forbidden paths, and
|
||||
completion obligations.
|
||||
Per-subsystem contracts: truth, extension points, forbidden paths, and
|
||||
completion obligations.
|
||||
11. `docs/release-control/v6/internal/RELEASE_PROMOTION_POLICY.md`
|
||||
Canonical stable-versus-prerelease promotion rules, rollout criteria, and rollback
|
||||
expectations for v6 and later release lines.
|
||||
Canonical stable-versus-prerelease promotion rules, rollout criteria, and rollback
|
||||
expectations for v6 and later release lines.
|
||||
12. `docs/release-control/v6/internal/V5_MAINTENANCE_SUPPORT_POLICY.md`
|
||||
Canonical v5 maintenance-only support policy, release-line rules, and GA
|
||||
notice requirements for the v6 cutover.
|
||||
Canonical v5 maintenance-only support policy, release-line rules, and GA
|
||||
notice requirements for the v6 cutover.
|
||||
13. `docs/release-control/v6/internal/RC_TO_GA_REHEARSAL_TEMPLATE.md`
|
||||
Canonical human record shape for the non-publish RC-to-GA rehearsal run.
|
||||
Canonical human record shape for the non-publish RC-to-GA rehearsal run.
|
||||
14. `docs/release-control/v6/internal/PLATFORM_SUPPORT_MODEL.md`
|
||||
Canonical first-class platform, ingestion-mode, resource-projection, and
|
||||
support-floor model for Pulse v6.
|
||||
Canonical first-class platform, ingestion-mode, resource-projection, and
|
||||
support-floor model for Pulse v6.
|
||||
|
||||
These machine files remain canonical, but agents should not ingest them in full
|
||||
by default when a smaller derived command answers the question. Prefer
|
||||
|
|
@ -126,13 +126,15 @@ infrastructure.
|
|||
Pulse should win by giving operators one coherent place to monitor,
|
||||
investigate, and safely act across mixed estates rather than by accumulating
|
||||
opportunistic platform-specific surfaces.
|
||||
The strong user-facing shape is a protection posture plus action queue, not an
|
||||
AI chat destination: Home answers "Am I protected?", Needs Attention answers
|
||||
"What needs me?", Explore/dashboard surfaces remain for browsing, Assistant is
|
||||
contextual explanation for the selected thing, and Patrol is the engine under
|
||||
the surface. This direction must stay simple enough for a new operator to
|
||||
understand without learning internal terms such as Intelligence, Patrol runs,
|
||||
handoffs, workflow starters, or findings lifecycle before they can act.
|
||||
The strong user-facing shape is monitor-first with contextual action, not an AI
|
||||
chat destination and not a generic Home front door: platform/dashboard surfaces
|
||||
open directly for browsing the estate, Patrol remains the visible checking-loop
|
||||
destination for findings and approvals, Assistant is contextual explanation for
|
||||
the selected thing, and posture/coverage summaries appear in context rather
|
||||
than replacing the monitoring landing path. This direction must stay simple
|
||||
enough for a new operator to understand without learning internal terms such as
|
||||
Intelligence, handoffs, workflow starters, or findings lifecycle before they
|
||||
can act.
|
||||
Steady-state value is part of the product truth: a calm estate should show
|
||||
coverage, freshness, drift, connectivity, and verification posture rather than
|
||||
feeling empty or dead.
|
||||
|
|
@ -469,36 +471,36 @@ Assertion design rules:
|
|||
7. Stable or GA promotion for v6 must come from an exercised RC and stay
|
||||
blocked until the RC-to-GA promotion gate is cleared and the published v5
|
||||
maintenance-policy notice is ready.
|
||||
7. v6 and later releases use a promotion model, not a direct broad-rollout
|
||||
8. v6 and later releases use a promotion model, not a direct broad-rollout
|
||||
model.
|
||||
`stable` must receive only promoted, already-validated builds, `rc` is the
|
||||
opt-in preview channel, and unattended auto-update exposure remains
|
||||
`stable`-only unless a new channel policy is explicitly adopted.
|
||||
8. Once v6 reaches stable or GA, v5 enters a 90-day maintenance-only window:
|
||||
9. Once v6 reaches stable or GA, v5 enters a 90-day maintenance-only window:
|
||||
critical security issues, critical correctness/data-loss issues, and safe
|
||||
migration blockers only. The exact end-of-support date must be published in
|
||||
the GA release notice. After that window, v5 is unsupported.
|
||||
9. Paid Pulse Pro v5 customers keep their existing recurring price through the
|
||||
v6 pricing change until they cancel. Renewal and entitlement continuity
|
||||
must preserve that grandfathered price state; any return after cancellation
|
||||
must use current v6 pricing.
|
||||
10. Pulse Mobile does not need desktop parity to stop blocking the v6 prerelease line.
|
||||
10. Paid Pulse Pro v5 customers keep their existing recurring price through the
|
||||
v6 pricing change until they cancel. Renewal and entitlement continuity
|
||||
must preserve that grandfathered price state; any return after cancellation
|
||||
must use current v6 pricing.
|
||||
11. Pulse Mobile does not need desktop parity to stop blocking the v6 prerelease line.
|
||||
The mobile usefulness floor for prerelease is narrower: preserve at least one
|
||||
trusted paired instance across relaunches, expose relay/runtime state
|
||||
clearly in the main shell, fail closed into a recoverable disconnected
|
||||
state on stale or revoked access, and keep live approvals useful and
|
||||
recoverable. Broader parity and expansion remain post-prerelease scope.
|
||||
11. The minimum required update set for canonical work is a floor, not a lane
|
||||
12. The minimum required update set for canonical work is a floor, not a lane
|
||||
closure rule. Agents should push the current lane to a coherent,
|
||||
defensible stop point and complete the next obvious same-lane work when it
|
||||
is necessary for trustworthy results, then normalize any remaining valid
|
||||
gap instead of calling the lane done by default.
|
||||
12. Unified-resource change history is the canonical durable backend timeline.
|
||||
13. Unified-resource change history is the canonical durable backend timeline.
|
||||
Alert incident memory may retain investigation-local notes, analysis,
|
||||
commands, runbooks, and alert lifecycle breadcrumbs, but it must remain a
|
||||
derived incident projection rather than a competing source of truth for
|
||||
durable resource history.
|
||||
13. Pulse v6 GA is feature-complete relative to the prerelease issue set.
|
||||
14. Pulse v6 GA is feature-complete relative to the prerelease issue set.
|
||||
Stable or GA must remain blocked until every known RC-era user-visible
|
||||
issue intended for v6 is fixed in the candidate, proven invalid with
|
||||
evidence, or conservatively superseded with the original problem resolved
|
||||
|
|
@ -636,25 +638,25 @@ claim stays blocked until live proof passes.
|
|||
assistant read behavior. If those proofs do not hold, implementation
|
||||
should stop at governance rather than shipping an inflated support claim.
|
||||
10. Execution sequence:
|
||||
VMware phase-1 execution should follow
|
||||
`docs/release-control/v6/internal/VMWARE_VSPHERE_PHASE1_EXECUTION_PLAN.md`
|
||||
as the concrete slice order and stop/go contract for the first admitted
|
||||
VMware support floor.
|
||||
VMware phase-1 execution should follow
|
||||
`docs/release-control/v6/internal/VMWARE_VSPHERE_PHASE1_EXECUTION_PLAN.md`
|
||||
as the concrete slice order and stop/go contract for the first admitted
|
||||
VMware support floor.
|
||||
11. Projection contract:
|
||||
VMware phase-1 projection should also follow
|
||||
`docs/release-control/v6/internal/VMWARE_VCENTER_PHASE1_RESOURCE_PROJECTION_SPEC.md`
|
||||
as the canonical source, identity, topology, alert-mapping, and
|
||||
non-projection boundary for phase-1 VMware resources.
|
||||
VMware phase-1 projection should also follow
|
||||
`docs/release-control/v6/internal/VMWARE_VCENTER_PHASE1_RESOURCE_PROJECTION_SPEC.md`
|
||||
as the canonical source, identity, topology, alert-mapping, and
|
||||
non-projection boundary for phase-1 VMware resources.
|
||||
12. Alerts and Assistant contract:
|
||||
VMware phase-1 alerts and Assistant work should also follow
|
||||
`docs/release-control/v6/internal/VMWARE_VCENTER_PHASE1_ALERTS_AND_ASSISTANT_SPEC.md`
|
||||
as the canonical shared-alert, shared-timeline, Assistant-read, and
|
||||
Assistant-control-exclusion boundary for the VMware phase-1 floor.
|
||||
VMware phase-1 alerts and Assistant work should also follow
|
||||
`docs/release-control/v6/internal/VMWARE_VCENTER_PHASE1_ALERTS_AND_ASSISTANT_SPEC.md`
|
||||
as the canonical shared-alert, shared-timeline, Assistant-read, and
|
||||
Assistant-control-exclusion boundary for the VMware phase-1 floor.
|
||||
13. Backend API/runtime contract:
|
||||
VMware phase-1 backend API/runtime work should also follow
|
||||
`docs/release-control/v6/internal/VMWARE_VCENTER_PHASE1_API_RUNTIME_SPEC.md`
|
||||
as the canonical public API-boundary, session-ownership, provider-health,
|
||||
and negative-space contract for the VMware phase-1 floor.
|
||||
VMware phase-1 backend API/runtime work should also follow
|
||||
`docs/release-control/v6/internal/VMWARE_VCENTER_PHASE1_API_RUNTIME_SPEC.md`
|
||||
as the canonical public API-boundary, session-ownership, provider-health,
|
||||
and negative-space contract for the VMware phase-1 floor.
|
||||
|
||||
## Cross-Repo Contracts
|
||||
|
||||
|
|
|
|||
|
|
@ -1,14 +1,16 @@
|
|||
# Protection Posture And Attention Queue Strong Version - 2026-06-25
|
||||
# Monitor-First Patrol Workbench Strong Version - 2026-06-25
|
||||
|
||||
## Decision
|
||||
|
||||
Pulse should present as an operator workbench for mixed private infrastructure,
|
||||
not as an AI assistant. The simple user model is:
|
||||
Pulse should present as a monitor-first operator workbench for mixed private
|
||||
infrastructure, not as an AI assistant and not as a summary page that delays
|
||||
monitoring. The simple user model is:
|
||||
|
||||
1. Home answers "Am I protected?"
|
||||
2. Needs Attention answers "What needs me?"
|
||||
3. Explore/dashboard surfaces answer "Let me look around."
|
||||
4. Assistant answers "Help me understand this specific thing."
|
||||
1. Monitoring pages answer "Show me my estate now."
|
||||
2. Patrol answers "What did the checking loop find, and what should I do?"
|
||||
3. Assistant answers "Help me understand this specific thing."
|
||||
4. Coverage/posture summaries answer "Am I protected?" only when the operator
|
||||
explicitly opens that posture view or contextual expansion.
|
||||
5. Patrol watches, investigates, proposes, acts within policy, verifies, and
|
||||
records outcomes underneath those surfaces.
|
||||
|
||||
|
|
@ -19,17 +21,15 @@ simple, calm-day useful, and action-oriented.
|
|||
|
||||
## North Star
|
||||
|
||||
Pulse watches my estate, tells me whether I am protected, and shows only the
|
||||
things I need to act on.
|
||||
Pulse opens directly into monitoring, keeps Patrol as the understood checking
|
||||
loop, and routes the operator from real findings/evidence to safe action.
|
||||
|
||||
## Strong-Version Checklist
|
||||
|
||||
- [ ] Home is a calm-day protection posture surface, not a marketing page and
|
||||
not a Patrol status console.
|
||||
- [ ] Home shows coverage/freshness posture for backups, agents, alerts,
|
||||
storage, recent changes, approvals, and last verification.
|
||||
- [ ] Needs Attention is a first-class primary destination for open work.
|
||||
- [ ] Needs Attention groups operator work across findings, approvals, failed
|
||||
- [x] Authenticated launch remains monitor-first: do not make a generic Home
|
||||
or posture page the default landing surface.
|
||||
- [x] Patrol remains the visible destination name for the checking loop.
|
||||
- [ ] Patrol groups operator work across findings, approvals, failed
|
||||
checks, stale protection, risky drift, recurring issues, and unresolved
|
||||
incidents.
|
||||
- [ ] Each item uses plain language: problem, affected thing, why it matters,
|
||||
|
|
@ -48,9 +48,9 @@ things I need to act on.
|
|||
- [ ] Recommendations expose trust scaffolding: evidence, confidence/reason,
|
||||
scope or blast radius, proposed action, approval requirement,
|
||||
verification result, and attempt history.
|
||||
- [ ] Calm-day empty states feel alive and useful: they show protection,
|
||||
freshness, coverage, drift, and verification posture instead of just
|
||||
"nothing here."
|
||||
- [ ] Calm-day monitoring and Patrol empty states feel alive and useful: they
|
||||
show protection, freshness, coverage, drift, and verification posture in
|
||||
context instead of just "nothing here."
|
||||
- [ ] Mobile and desktop use the same mental model: status/protection first,
|
||||
next action second, contextual explanation third.
|
||||
- [ ] Settings, docs, command palette, and onboarding stop promoting generic
|
||||
|
|
@ -72,24 +72,27 @@ things I need to act on.
|
|||
|
||||
1. Capture the product target in governance and tests so context compaction
|
||||
cannot erase it.
|
||||
2. Reframe existing Patrol/current-work copy toward Needs Attention language
|
||||
without breaking the current L23 floor.
|
||||
3. Build the calm-day Home posture model and wire it to real runtime data.
|
||||
4. Promote Needs Attention as the primary work queue.
|
||||
2. Keep Patrol as the visible checking-loop destination while clarifying open
|
||||
findings, approvals, and verification state inside the page.
|
||||
3. Preserve monitor-first launch behavior and avoid a generic Home front door.
|
||||
4. Add calm-day posture only as contextual monitoring/Patrol evidence, not as
|
||||
the default landing page.
|
||||
5. Demote generic Assistant entry points to contextual explain/review actions.
|
||||
6. Tighten trust scaffolding and autonomy presentation across the queue.
|
||||
7. Validate in browser across desktop/mobile active-work and calm-day states.
|
||||
|
||||
## Progress
|
||||
|
||||
- 2026-06-25: The existing Patrol route, browser title, utility nav item,
|
||||
command palette entry, and keyboard shortcut copy now lead with
|
||||
`Needs Attention`. The inner work queue uses `Open work` to avoid repeating
|
||||
the page title, while Patrol remains visible as the engine in mode, run,
|
||||
history, and settings controls. Browser proof covered the active-work state
|
||||
on desktop and mobile. This completes the first UI naming slice only; it does
|
||||
not complete the Home posture model, full cross-source queue, Assistant
|
||||
demotion, or calm-day validation.
|
||||
- 2026-06-25: Product correction: do not make Home the primary landing page,
|
||||
and do not rename the Patrol destination to `Needs Attention`. Users already
|
||||
understand Patrol as the checking loop. The route, browser title, shell nav,
|
||||
command palette, and shortcut copy should lead with `Patrol`; `Open work`,
|
||||
findings, approvals, and "needs attention" remain page/status language inside
|
||||
Patrol where they explain the work.
|
||||
- 2026-06-25: Implemented the correction in the desktop shell, mobile shell,
|
||||
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.
|
||||
|
||||
## Evidence
|
||||
|
||||
|
|
@ -104,9 +107,10 @@ things I need to act on.
|
|||
|
||||
## Residuals
|
||||
|
||||
- The first implementation slice does not implement the new Home posture model
|
||||
or the full cross-source Needs Attention queue.
|
||||
- The exact nav labels remain product decisions, but the job names are fixed:
|
||||
protected posture, needs attention, and exploration.
|
||||
- Cross-source current-work grouping remains useful, but it belongs inside
|
||||
Patrol or contextual monitoring surfaces rather than a renamed top-level
|
||||
destination.
|
||||
- Calm-day posture still needs a deliberately contextual design pass before it
|
||||
should be added to monitoring or Patrol.
|
||||
- The status coverage gap `protection-posture-attention-queue` tracks the
|
||||
remaining product-surface work.
|
||||
|
|
|
|||
|
|
@ -7235,7 +7235,7 @@
|
|||
},
|
||||
{
|
||||
"id": "protection-posture-attention-queue",
|
||||
"summary": "Pulse now has a durable strong-version product direction, but the current lane map does not yet model the simple user-facing shape as one governed surface: Home should answer whether the estate is protected, Needs Attention should be the primary action queue, Explore should preserve dashboard browsing, Assistant should explain the selected thing, and Patrol should remain the engine underneath. Without an explicit lane-expansion record, work can drift into local Patrol renames, generic Assistant polish, or an inbox that feels dead in steady state instead of proving calm-day protection posture.",
|
||||
"summary": "Pulse now has a durable strong-version product direction, but the current lane map does not yet model the simple user-facing shape as one governed surface: authenticated launch stays monitor-first on platform and dashboard surfaces, Patrol remains the named checking-loop destination for findings, approvals, and explain-act-verify work, Assistant explains selected context, and protection posture or coverage signals appear in the relevant monitor and Patrol contexts instead of a generic Home front door. Without an explicit lane-expansion record, work can drift into Home-first surfaces, Patrol renames, generic Assistant polish, or read-only object-browser copies instead of proving simple monitor-first operations.",
|
||||
"owner": "project-owner",
|
||||
"status": "planned",
|
||||
"recorded_at": "2026-06-25",
|
||||
|
|
@ -7306,8 +7306,8 @@
|
|||
},
|
||||
{
|
||||
"id": "protection-posture-attention-queue",
|
||||
"name": "Protection Posture And Attention Queue",
|
||||
"summary": "Promote the strong-version operator workbench into a governed lane expansion covering calm-day Home protection posture, the primary Needs Attention action queue, dashboard Explore boundaries, contextual Assistant demotion, Patrol as the underlying engine, explicit autonomy/trust scaffolding, and browser proof for both active-work and calm-day states.",
|
||||
"name": "Monitor-First Patrol Workbench",
|
||||
"summary": "Promote the corrected strong-version operator workbench into a governed lane expansion covering monitor-first launch, Patrol as the visible checking-loop surface, contextual Assistant demotion, safe action and verification flows, calm-day coverage posture in context, dashboard Explore boundaries, explicit autonomy and trust scaffolding, and browser proof for both active-work and calm-day states.",
|
||||
"status": "planned",
|
||||
"recorded_at": "2026-06-25",
|
||||
"target_id": "v6-product-lane-expansion",
|
||||
|
|
|
|||
|
|
@ -3805,11 +3805,10 @@ was clarified on 2026-05-25 and 2026-06-25 through `frontend-modern/src/App.tsx`
|
|||
`frontend-modern/src/AppLayout.tsx`: the top of the app may expose canonical
|
||||
platform pages (Proxmox, Kubernetes, TrueNAS, vSphere) plus the
|
||||
Docker / Podman container-runtime lens (shown as Docker in the shell), aggregate
|
||||
platform-owned Workloads / Storage / Recovery sub-surfaces, Alerts,
|
||||
Needs Attention, and Settings. `Needs Attention` is the visible destination for
|
||||
Patrol-owned operator work; it must still route through the canonical `/patrol`
|
||||
surface and must not create a second Assistant, Patrol, or Intelligence route
|
||||
namespace.
|
||||
platform-owned Workloads / Storage / Recovery sub-surfaces, Alerts, Patrol, and
|
||||
Settings. `Patrol` is the visible destination for Patrol-owned operator work; it
|
||||
must route through the canonical `/patrol` surface and must not create a second
|
||||
Assistant or Intelligence route namespace.
|
||||
Provider/runtime destinations must pass the shared support-and-resource-
|
||||
evidence gate before they appear in navigation, command palette entries,
|
||||
keyboard shortcuts, or landing fallbacks. Aggregate workspace tabs are retired
|
||||
|
|
|
|||
|
|
@ -264,10 +264,10 @@ registry resource. Pending approvals and active findings are current operator
|
|||
work and must outrank older completed/resolved loop proof when the route chooses
|
||||
`nextAction` and step status. Historical Patrol control proof remains recorded
|
||||
as count-only value evidence, but it must render as history until the current
|
||||
finding or approval is handled. Browser presentation may label the route
|
||||
`Needs Attention` and the default queue `Open work`, but those labels are chrome
|
||||
over this existing status/finding/approval contract; they are not new API
|
||||
fields, prompt payloads, or alternate current-work schemas.
|
||||
finding or approval is handled. Browser presentation labels the route `Patrol`
|
||||
and may label the default queue `Open work`, but those labels are chrome over
|
||||
this existing status/finding/approval contract; they are not new API fields,
|
||||
prompt payloads, or alternate current-work schemas.
|
||||
The authenticated `GET /api/agent/patrol-control/status` projection exposes the same content-free starter evidence as count-only fields
|
||||
(`operationsLoopStarterCount`, `assistantOperationsLoopStarterCount`,
|
||||
`patrolOperationsLoopStarterCount`,
|
||||
|
|
@ -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 `Needs Attention` 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 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
|
||||
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
|
||||
|
|
|
|||
|
|
@ -819,10 +819,10 @@ or other self-hosted uncapped continuity plans.
|
|||
App-shell navigation rendered by `frontend-modern/src/AppLayout.tsx` must
|
||||
also keep decorative icon titles out of tab accessible names, so hosted and
|
||||
self-hosted chrome announce the canonical tab label plus meaningful badge
|
||||
counts rather than duplicating branded SVG titles. Renaming the Patrol-owned
|
||||
utility destination to `Needs Attention` is shell chrome over the same
|
||||
`/patrol` route; it must not alter hosted org bootstrap, entitlement loading,
|
||||
or commercial posture loading.
|
||||
counts rather than duplicating branded SVG titles. The Patrol-owned utility
|
||||
destination remains `Patrol` over the same `/patrol` route; it must not
|
||||
alter hosted org bootstrap, entitlement loading, or commercial posture
|
||||
loading.
|
||||
Retired operator top-level route compatibility in
|
||||
`frontend-modern/src/App.tsx` must stay inside authenticated app-owned
|
||||
surfaces such as Infrastructure, Workloads, Storage, and Recovery. Those
|
||||
|
|
@ -972,9 +972,9 @@ hands-on Patrol modes, issue investigation, verified fixes, and longer history`.
|
|||
`standalone` route/id, is not a new commercial usage unit: hosted and paid
|
||||
surfaces continue to meter the governed monitored-system grouping result
|
||||
rather than counting primary navigation destinations.
|
||||
The user-facing `Needs Attention` utility tab is likewise not a commercial
|
||||
plan or usage unit; it remains the Patrol-owned daily work entrypoint over
|
||||
current findings, approvals, and verification state.
|
||||
The user-facing `Patrol` utility tab is likewise not a commercial plan or
|
||||
usage unit; it remains the Patrol-owned daily work entrypoint over current
|
||||
findings, approvals, and verification state.
|
||||
Landing behavior for paid and hosted shells must also defer to the
|
||||
frontend-primitives-owned provider-first landing contract instead of
|
||||
defining a cloud-paid-specific order.
|
||||
|
|
|
|||
|
|
@ -9,7 +9,11 @@
|
|||
"contract_file": "docs/release-control/v6/internal/subsystems/frontend-primitives.md",
|
||||
"status_file": "docs/release-control/v6/internal/status.json",
|
||||
"registry_file": "docs/release-control/v6/internal/subsystems/registry.json",
|
||||
"dependency_subsystem_ids": ["agent-lifecycle", "cloud-paid", "storage-recovery"]
|
||||
"dependency_subsystem_ids": [
|
||||
"agent-lifecycle",
|
||||
"cloud-paid",
|
||||
"storage-recovery"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
|
|
@ -85,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 Needs Attention 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 Needs Attention while the default workspace underneath uses 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 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)
|
||||
62. `frontend-modern/src/components/SetupWizard/SetupWizard.tsx`
|
||||
63. `frontend-modern/src/components/Settings/useSettingsInfrastructurePanelProps.ts`
|
||||
64. `frontend-modern/src/components/SetupWizard/SetupCompletionPreview.tsx`
|
||||
|
|
|
|||
|
|
@ -185,10 +185,11 @@ attention`, `approval needed`, `outcome verified`, `no active work`) instead
|
|||
unexplained `95/100` telemetry.
|
||||
The Patrol workspace must default to current operator work: current findings,
|
||||
active investigations, approval decisions, and selected finding snapshots.
|
||||
The route and page title must lead with `Needs Attention`, and the default
|
||||
workspace title underneath it must be `Open work` so the page does not repeat
|
||||
the same accessible heading while still answering what needs the operator
|
||||
now. Patrol remains the underlying watch/investigate/act/verify engine. The
|
||||
The route and page title must lead with `Patrol`, because operators
|
||||
understand Patrol as the recurring checking loop. The default workspace title
|
||||
underneath it may use `Open work` so the page can explain current findings
|
||||
and approvals without renaming the destination. Patrol remains the
|
||||
watch/investigate/act/verify engine. The
|
||||
exception is a
|
||||
setup-only Patrol runtime failure: that state must use the `Fix Patrol setup`
|
||||
title and setup description while rendering a dedicated setup task instead of
|
||||
|
|
@ -481,7 +482,7 @@ attention`, `approval needed`, `outcome verified`, `no active work`) instead
|
|||
with recent snapshots and keep older runs behind an explicit expansion, while
|
||||
preserving full forensic access for operators who deliberately open it.
|
||||
Individual run entries must read as an operator action record first (`All
|
||||
clear`, `Found N new issues`, `Fixed N issues`, `N issues still open`, or
|
||||
clear`, `Found N new issues`, `Fixed N issues`, `N issues still open`, or
|
||||
`Patrol needs attention`) with checked-resource coverage as supporting
|
||||
detail. Trigger reason, duration, tool-call counts, tokens, triage flags,
|
||||
and raw tool traces are forensic context and must stay secondary to what
|
||||
|
|
@ -522,18 +523,18 @@ attention`, `approval needed`, `outcome verified`, `no active work`) instead
|
|||
tool-call observation, or readiness internals belong in Provider & Models
|
||||
and backend/test contracts, not in the first-party Patrol operator banner.
|
||||
5. Keep customer-facing Patrol naming product-first while preserving the
|
||||
operator-workbench job words: the daily work destination may lead with
|
||||
`Needs Attention`, while summary copy, actions, empty states, and mode
|
||||
controls should keep Patrol or Pulse Patrol as the watch/investigate/act
|
||||
engine rather than generic `AI` branding. Reserve `AI` terminology for
|
||||
operator-workbench job words inside the page: the daily work destination
|
||||
leads with `Patrol`, while summary copy, actions, empty states, and mode
|
||||
controls may describe findings, approvals, and work that needs attention.
|
||||
Reserve `AI` terminology for
|
||||
explicit provider/configuration settings, shared runtime internals, or other
|
||||
technical capability boundaries where the underlying ownership really is AI
|
||||
runtime rather than the Patrol product surface.
|
||||
6. Keep Patrol brand icon accessibility contextual: `PulsePatrolLogo` remains
|
||||
label-bearing when the icon stands alone, but Patrol headings and actions
|
||||
that already include visible Patrol or Needs Attention text must render the
|
||||
logo as decorative so accessible names do not repeat as `Pulse Patrol Needs
|
||||
Attention` or similar duplicated names.
|
||||
that already include visible Patrol text must render the logo as decorative
|
||||
so accessible names do not repeat as `Pulse Patrol Patrol` or similar
|
||||
duplicated names.
|
||||
7. Keep Patrol remediation copy operator-safe even while legacy transport
|
||||
fields retain `auto_fix` naming for compatibility: header autonomy controls,
|
||||
Pro-locked helper text, investigation outcome labels, and run-history badges
|
||||
|
|
|
|||
|
|
@ -210,7 +210,7 @@ export function AppLayout(props: AppLayoutProps) {
|
|||
vmware: 'vSphere',
|
||||
standalone: 'Machines',
|
||||
alerts: 'Alerts',
|
||||
ai: 'Needs Attention',
|
||||
ai: 'Patrol',
|
||||
settings: 'Settings',
|
||||
};
|
||||
createEffect(() => {
|
||||
|
|
@ -428,9 +428,9 @@ export function AppLayout(props: AppLayoutProps) {
|
|||
},
|
||||
{
|
||||
id: 'ai',
|
||||
label: 'Needs Attention',
|
||||
label: 'Patrol',
|
||||
route: '/patrol',
|
||||
tooltip: 'Review issues and approvals that need action',
|
||||
tooltip: 'Review Patrol checks, findings, and approvals',
|
||||
badge: null,
|
||||
count: undefined,
|
||||
breakdown: undefined,
|
||||
|
|
|
|||
|
|
@ -282,8 +282,8 @@ describe('App architecture', () => {
|
|||
expect(appLayoutSource).toContain("const blockedPrefixes = ['/settings', '/patrol'];");
|
||||
expect(appLayoutSource).not.toContain("'/operations', '/patrol', '/ai'");
|
||||
expect(appLayoutSource).toContain("route: '/patrol',");
|
||||
expect(appLayoutSource).toContain("label: 'Needs Attention'");
|
||||
expect(appLayoutSource).toContain("tooltip: 'Review issues and approvals that need action'");
|
||||
expect(appLayoutSource).toContain("label: 'Patrol'");
|
||||
expect(appLayoutSource).toContain("tooltip: 'Review Patrol checks, findings, and approvals'");
|
||||
expect(appLayoutSource).not.toContain("route: '/operations',");
|
||||
expect(appLayoutSource).not.toContain('props.connected()');
|
||||
expect(appLayoutSource).toContain('const utilityTabs = createMemo(() =>');
|
||||
|
|
|
|||
|
|
@ -94,18 +94,16 @@ describe('AppLayout navigation icons', () => {
|
|||
expect(tab.querySelector('svg')).toBeTruthy();
|
||||
});
|
||||
const desktopPatrolTab = within(systemGroup as HTMLElement).getByRole('tab', {
|
||||
name: 'Needs Attention',
|
||||
name: 'Patrol',
|
||||
});
|
||||
expect(desktopPatrolTab.querySelector('svg')).toBeTruthy();
|
||||
expect(within(systemGroup as HTMLElement).getByRole('tab', { name: '1 Alerts' })).toBeTruthy();
|
||||
expect(
|
||||
within(systemGroup as HTMLElement).queryByRole('tab', {
|
||||
name: 'Pulse Patrol Needs Attention',
|
||||
name: 'Pulse Patrol Patrol',
|
||||
}),
|
||||
).toBeNull();
|
||||
expect(
|
||||
within(systemGroup as HTMLElement).queryByRole('tab', { name: 'Needs Attention P' }),
|
||||
).toBeNull();
|
||||
expect(within(systemGroup as HTMLElement).queryByRole('tab', { name: 'Patrol P' })).toBeNull();
|
||||
|
||||
const mobileTablist = screen.getByRole('tablist', { name: 'Mobile navigation' });
|
||||
['alerts', 'ai', 'settings'].forEach((tabId) => {
|
||||
|
|
@ -114,7 +112,7 @@ describe('AppLayout navigation icons', () => {
|
|||
expect(button?.querySelector('svg')).toBeTruthy();
|
||||
});
|
||||
const mobilePatrolTab = within(mobileTablist).getByRole('button', {
|
||||
name: 'Needs Attention',
|
||||
name: 'Patrol',
|
||||
});
|
||||
expect(mobilePatrolTab.querySelector('svg')).toBeTruthy();
|
||||
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ const UNIFIED_NAV_SHORTCUTS: ShortcutGroup = {
|
|||
{ keys: 'g then n', description: 'Go to TrueNAS' },
|
||||
{ keys: 'g then v', description: 'Go to vSphere' },
|
||||
{ keys: 'g then a', description: 'Go to Alerts' },
|
||||
{ keys: 'g then r', description: 'Go to Needs Attention' },
|
||||
{ keys: 'g then r', description: 'Go to Patrol' },
|
||||
{ keys: 'g then t', description: 'Go to Settings' },
|
||||
],
|
||||
};
|
||||
|
|
|
|||
|
|
@ -126,8 +126,8 @@ describe('CommandPaletteModal', () => {
|
|||
expect(screen.queryByText('/storage')).not.toBeInTheDocument();
|
||||
expect(screen.queryByText('Go to Recovery')).not.toBeInTheDocument();
|
||||
expect(screen.queryByText('/recovery')).not.toBeInTheDocument();
|
||||
expect(screen.getByText('Go to Needs Attention')).toBeInTheDocument();
|
||||
expect(screen.queryByText('Go to Patrol')).not.toBeInTheDocument();
|
||||
expect(screen.getByText('Go to Patrol')).toBeInTheDocument();
|
||||
expect(screen.queryByText('Go to Needs Attention')).not.toBeInTheDocument();
|
||||
expect(screen.getByText('Go to vSphere')).toBeInTheDocument();
|
||||
expect(screen.getByText('Go to vSphere Networks')).toBeInTheDocument();
|
||||
expect(screen.getByText('/vmware/networks')).toBeInTheDocument();
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ describe('MobileNavBar', () => {
|
|||
utilityTabs={() => [
|
||||
{
|
||||
id: 'ai',
|
||||
label: 'Needs Attention',
|
||||
label: 'Patrol',
|
||||
route: '/patrol',
|
||||
tooltip: 'Continuous verification',
|
||||
badge: null,
|
||||
|
|
@ -77,12 +77,10 @@ describe('MobileNavBar', () => {
|
|||
));
|
||||
|
||||
const navList = screen.getByRole('tablist', { name: 'Mobile navigation' });
|
||||
const patrolButton = within(navList).getByRole('button', { name: 'Needs Attention' });
|
||||
const patrolButton = within(navList).getByRole('button', { name: 'Patrol' });
|
||||
|
||||
expect(patrolButton).toHaveAttribute('data-tab-id', 'ai');
|
||||
expect(
|
||||
within(navList).queryByRole('button', { name: 'Pulse Patrol Needs Attention' }),
|
||||
).toBeNull();
|
||||
expect(within(navList).queryByRole('button', { name: 'Pulse Patrol Patrol' })).toBeNull();
|
||||
});
|
||||
|
||||
it('allows inactive platform tabs to render without an active mobile tab', () => {
|
||||
|
|
|
|||
|
|
@ -243,7 +243,7 @@ export function buildCommandPaletteCommands(options: {
|
|||
},
|
||||
{
|
||||
id: 'nav-patrol',
|
||||
label: 'Go to Needs Attention',
|
||||
label: 'Go to Patrol',
|
||||
description: '/patrol',
|
||||
shortcut: 'g r',
|
||||
keywords: ['needs attention', 'patrol', 'findings', 'ai', 'verification'],
|
||||
|
|
|
|||
|
|
@ -618,12 +618,10 @@ describe('AIIntelligence entitlement gating', () => {
|
|||
render(() => <AIIntelligence />);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByRole('heading', { name: 'Needs Attention' })).toBeInTheDocument();
|
||||
expect(screen.getByRole('heading', { name: 'Patrol' })).toBeInTheDocument();
|
||||
});
|
||||
|
||||
expect(
|
||||
screen.queryByRole('heading', { name: 'Pulse Patrol Needs Attention' }),
|
||||
).not.toBeInTheDocument();
|
||||
expect(screen.queryByRole('heading', { name: 'Pulse Patrol Patrol' })).not.toBeInTheDocument();
|
||||
expect(screen.getByTestId('pulse-patrol-logo')).toHaveAttribute('aria-hidden', 'true');
|
||||
});
|
||||
|
||||
|
|
@ -633,7 +631,7 @@ describe('AIIntelligence entitlement gating', () => {
|
|||
render(() => <AIIntelligence />);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByRole('heading', { name: 'Needs Attention' })).toBeInTheDocument();
|
||||
expect(screen.getByRole('heading', { name: 'Patrol' })).toBeInTheDocument();
|
||||
});
|
||||
|
||||
expect(
|
||||
|
|
@ -876,7 +874,7 @@ describe('AIIntelligence entitlement gating', () => {
|
|||
render(() => <AIIntelligence />);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByRole('heading', { name: 'Needs Attention' })).toBeInTheDocument();
|
||||
expect(screen.getByRole('heading', { name: 'Patrol' })).toBeInTheDocument();
|
||||
});
|
||||
expect(screen.queryByText('Patrol setup issue')).not.toBeInTheDocument();
|
||||
expect(screen.queryByText('Patrol setup warning')).not.toBeInTheDocument();
|
||||
|
|
@ -980,7 +978,7 @@ describe('AIIntelligence entitlement gating', () => {
|
|||
render(() => <AIIntelligence />);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByRole('heading', { name: 'Needs Attention' })).toBeInTheDocument();
|
||||
expect(screen.getByRole('heading', { name: 'Patrol' })).toBeInTheDocument();
|
||||
});
|
||||
expect(screen.queryByRole('button', { name: 'Details' })).not.toBeInTheDocument();
|
||||
expect(screen.queryByRole('button', { name: 'Hide details' })).not.toBeInTheDocument();
|
||||
|
|
@ -1167,7 +1165,7 @@ describe('AIIntelligence entitlement gating', () => {
|
|||
render(() => <AIIntelligence />);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByRole('heading', { name: 'Needs Attention' })).toBeInTheDocument();
|
||||
expect(screen.getByRole('heading', { name: 'Patrol' })).toBeInTheDocument();
|
||||
});
|
||||
await waitFor(() => {
|
||||
expect(apiFetchJSONMock).toHaveBeenCalledWith('/api/ai/models');
|
||||
|
|
@ -1282,7 +1280,7 @@ describe('AIIntelligence entitlement gating', () => {
|
|||
expect(getPatrolRunHistoryMock.mock.calls.length).toBeGreaterThan(
|
||||
runHistoryCallsBeforeModeChange,
|
||||
);
|
||||
expect(screen.getByRole('heading', { name: 'Needs Attention' })).toBeInTheDocument();
|
||||
expect(screen.getByRole('heading', { name: 'Patrol' })).toBeInTheDocument();
|
||||
expect(screen.queryByTestId('patrol-current-work')).not.toBeInTheDocument();
|
||||
expect(screen.queryByText('Patrol ready')).not.toBeInTheDocument();
|
||||
expect(screen.queryByText(/Run Patrol now to look for issues/)).not.toBeInTheDocument();
|
||||
|
|
@ -1358,7 +1356,7 @@ describe('AIIntelligence entitlement gating', () => {
|
|||
|
||||
await waitFor(() => {
|
||||
expect(getPatrolStatusMock).toHaveBeenCalled();
|
||||
expect(screen.getByRole('heading', { name: 'Needs Attention' })).toBeInTheDocument();
|
||||
expect(screen.getByRole('heading', { name: 'Patrol' })).toBeInTheDocument();
|
||||
});
|
||||
|
||||
expect(screen.queryByText('Patrol status')).not.toBeInTheDocument();
|
||||
|
|
@ -1383,7 +1381,7 @@ describe('AIIntelligence entitlement gating', () => {
|
|||
));
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByRole('heading', { name: 'Needs Attention' })).toBeInTheDocument();
|
||||
expect(screen.getByRole('heading', { name: 'Patrol' })).toBeInTheDocument();
|
||||
expect(screen.getByText('Open work')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
|
|
@ -1402,7 +1400,7 @@ describe('AIIntelligence entitlement gating', () => {
|
|||
));
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByRole('heading', { name: 'Needs Attention' })).toBeInTheDocument();
|
||||
expect(screen.getByRole('heading', { name: 'Patrol' })).toBeInTheDocument();
|
||||
expect(screen.getByText('Patrol could not refresh')).toBeInTheDocument();
|
||||
expect(screen.getByText('Open work')).toBeInTheDocument();
|
||||
});
|
||||
|
|
@ -2211,7 +2209,7 @@ describe('AIIntelligence entitlement gating', () => {
|
|||
|
||||
await waitFor(() => {
|
||||
expect(getPatrolRunHistoryMock).toHaveBeenCalled();
|
||||
expect(screen.getByRole('heading', { name: 'Needs Attention' })).toBeInTheDocument();
|
||||
expect(screen.getByRole('heading', { name: 'Patrol' })).toBeInTheDocument();
|
||||
});
|
||||
|
||||
expect(screen.queryByText(/No active issues · health score 100\/100/)).not.toBeInTheDocument();
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import type { PatrolAutonomyLevel } from '@/api/patrol';
|
||||
|
||||
export const PATROL_PAGE_TITLE = 'Needs Attention';
|
||||
export const PATROL_PAGE_TITLE = 'Patrol';
|
||||
|
||||
export const PATROL_PAGE_WATCH_ONLY_DESCRIPTION =
|
||||
'Patrol watches infrastructure and shows current issues.';
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue