From 500d3be2a7ec8506da9fe2850395535b660e8829 Mon Sep 17 00:00:00 2001 From: rcourtman Date: Sat, 11 Jul 2026 09:33:47 +0100 Subject: [PATCH] Align Pro feature catalog names with the new Patrol vocabulary The public pricing surface and in-app plan-selling copy now say "Patrol investigates issues and explains the root cause" and "Patrol applies safe fixes and verifies the result". Rename the licensing catalog DisplayName/ComparisonName pairs to the title-cased forms, align the ai_autofix UpgradeReason verbs (apply/verify the result), regenerate the frontend catalog, and update the Go, vitest, and Playwright pins plus README and PULSE_PRO docs. --- README.md | 4 +- docs/PULSE_PRO.md | 4 +- .../__tests__/ProLicensePanel.test.tsx | 16 ++--- .../licensePresentation.coverage.test.ts | 16 ++--- .../__tests__/licensePresentation.test.ts | 64 +++++++++---------- .../utils/__tests__/selfHostedPlans.test.ts | 4 +- .../selfHostedFeatureCatalog.generated.ts | 8 +-- internal/api/contract_test.go | 2 +- internal/license/coverage_additional_test.go | 4 +- pkg/licensing/features_test.go | 4 +- pkg/licensing/self_hosted_feature_catalog.go | 10 +-- pkg/licensing/upgrade_test.go | 2 +- .../55-self-hosted-upgrade-return.spec.ts | 6 +- 13 files changed, 72 insertions(+), 72 deletions(-) diff --git a/README.md b/README.md index 29f5713bf..0cd56be13 100644 --- a/README.md +++ b/README.md @@ -209,8 +209,8 @@ Runtime-aligned capability summary: |---|:---:|:---:|:---:|:---:| | Pulse Patrol (Background Health Checks) | ✅ | ✅ | ✅ | ✅ | | Remote Access / Mobile / Push | — | ✅ | ✅ | ✅ | -| Patrol Investigates Issues | — | — | ✅ | ✅ | -| Patrol Handles Safe Fixes | — | — | ✅ | ✅ | +| Patrol Investigates Issues and Explains the Root Cause | — | — | ✅ | ✅ | +| Patrol Applies Safe Fixes and Verifies the Result | — | — | ✅ | ✅ | | Centralized Agent Profiles | — | — | ✅ | ✅ | | Update Alerts (Container/Package Updates) | ✅ | ✅ | ✅ | ✅ | | SSO (OIDC/SAML/Multi-Provider) | ✅ | ✅ | ✅ | ✅ | diff --git a/docs/PULSE_PRO.md b/docs/PULSE_PRO.md index 8b2413476..b9f0a812e 100644 --- a/docs/PULSE_PRO.md +++ b/docs/PULSE_PRO.md @@ -140,8 +140,8 @@ This matrix is derived from the canonical table in `docs/architecture/ENTITLEMEN |---|---|---|:---:|:---:|:---:|:---:|---| | `FeatureAIPatrol` | `ai_patrol` | Pulse Patrol (Background Health Checks) | Y | Y | Y | Y | Patrol itself is available on Community with your own provider or local model. Higher-autonomy outcomes and fix execution are separately gated. | | `FeatureRelay` | `relay` | Remote Access (Mobile Relay) | N | Y | Y | Y | API route gating via `RequireLicenseFeature(..., relay, ...)` for relay settings and onboarding endpoints. | -| `FeatureAIAlerts` | `ai_alerts` | Patrol Investigates Issues | N | N | Y | Y | API route gating via `RequireLicenseFeature(..., ai_alerts, ...)`. | -| `FeatureAIAutoFix` | `ai_autofix` | Patrol Handles Safe Fixes | N | N | Y | Y | Required for governed fix execution and automatic Patrol actions. | +| `FeatureAIAlerts` | `ai_alerts` | Patrol Investigates Issues and Explains the Root Cause | N | N | Y | Y | API route gating via `RequireLicenseFeature(..., ai_alerts, ...)`. | +| `FeatureAIAutoFix` | `ai_autofix` | Patrol Applies Safe Fixes and Verifies the Result | N | N | Y | Y | Required for governed fix execution and automatic Patrol actions. | | `FeatureKubernetesAI` | `kubernetes_ai` | Kubernetes AI Analysis (Compatibility) | N | N | Y | Y | Legacy compatibility gate for `/api/ai/kubernetes/analyze`; not a primary marketed v6 Pro plan pillar. | | `FeatureAgentProfiles` | `agent_profiles` | Centralized Agent Profiles | N | N | Y | Y | API route gating via `RequireLicenseFeature(..., agent_profiles, ...)`. | | `FeatureUpdateAlerts` | `update_alerts` | Update Alerts (Container/Package Updates) | Y | Y | Y | Y | Included in Community tier per `TierFeatures[TierFree]`. | diff --git a/frontend-modern/src/components/Settings/__tests__/ProLicensePanel.test.tsx b/frontend-modern/src/components/Settings/__tests__/ProLicensePanel.test.tsx index eb15810ab..3590b5810 100644 --- a/frontend-modern/src/components/Settings/__tests__/ProLicensePanel.test.tsx +++ b/frontend-modern/src/components/Settings/__tests__/ProLicensePanel.test.tsx @@ -398,7 +398,7 @@ describe('ProLicensePanel', () => { expect(screen.getAllByText('Trial').length).toBeGreaterThan(0); expect(screen.getByText('7')).toBeInTheDocument(); - expect(screen.getByText('Patrol Handles Safe Fixes')).toBeInTheDocument(); + expect(screen.getByText('Patrol Applies Safe Fixes and Verifies the Result')).toBeInTheDocument(); }); it('keeps the Patrol mode entry point visible for existing active Pro plans', async () => { @@ -836,8 +836,8 @@ describe('ProLicensePanel', () => { ), ).toBeInTheDocument(); expect(screen.getByText('Primary capabilities')).toBeInTheDocument(); - expect(screen.getByText('Patrol Investigates Issues')).toBeInTheDocument(); - expect(screen.getByText('Patrol Handles Safe Fixes')).toBeInTheDocument(); + expect(screen.getByText('Patrol Investigates Issues and Explains the Root Cause')).toBeInTheDocument(); + expect(screen.getByText('Patrol Applies Safe Fixes and Verifies the Result')).toBeInTheDocument(); expect(screen.getByText('Included extras')).toBeInTheDocument(); expect(screen.getByText('Capability details')).toBeInTheDocument(); expect(screen.getByText('(5 items ready)')).toBeInTheDocument(); @@ -1085,8 +1085,8 @@ describe('ProLicensePanel', () => { // Verify self-hosted displayable capabilities render with their expected labels. expect(screen.getByText('Pulse Patrol')).toBeInTheDocument(); - expect(screen.getByText('Patrol Investigates Issues')).toBeInTheDocument(); - expect(screen.getByText('Patrol Handles Safe Fixes')).toBeInTheDocument(); + expect(screen.getByText('Patrol Investigates Issues and Explains the Root Cause')).toBeInTheDocument(); + expect(screen.getByText('Patrol Applies Safe Fixes and Verifies the Result')).toBeInTheDocument(); expect(screen.getByText('Update Alerts')).toBeInTheDocument(); expect(screen.getByText('Role-Based Access Control (RBAC)')).toBeInTheDocument(); expect(screen.getByText('Audit Logging')).toBeInTheDocument(); @@ -1195,7 +1195,7 @@ describe('ProLicensePanel', () => { ), ).toBeInTheDocument(); expect(screen.getByText('Available now on this instance')).toBeInTheDocument(); - expect(screen.getAllByText('Patrol Handles Safe Fixes').length).toBeGreaterThan(0); + expect(screen.getAllByText('Patrol Applies Safe Fixes and Verifies the Result').length).toBeGreaterThan(0); expect(screen.getAllByRole('link', { name: 'Choose Patrol mode' })).toHaveLength(1); const patrolControlLink = screen.getByRole('link', { name: 'Choose Patrol mode' }); expect(patrolControlLink).toHaveAttribute('href', PATROL_CONTROL_STARTER_URL); @@ -1285,7 +1285,7 @@ describe('ProLicensePanel', () => { ), ).toBeInTheDocument(); expect(screen.queryByText('Select a plan')).not.toBeInTheDocument(); - expect(screen.getAllByText('Patrol Handles Safe Fixes').length).toBeGreaterThan(0); + expect(screen.getAllByText('Patrol Applies Safe Fixes and Verifies the Result').length).toBeGreaterThan(0); expect(screen.queryByText('Available plans')).not.toBeInTheDocument(); expect(screen.queryByRole('link', { name: 'Review plan' })).not.toBeInTheDocument(); }); @@ -1310,7 +1310,7 @@ describe('ProLicensePanel', () => { ), ).not.toBeInTheDocument(); expect(screen.getByText('Current plan: Community')).toBeInTheDocument(); - expect(screen.queryByText('Patrol Handles Safe Fixes')).not.toBeInTheDocument(); + expect(screen.queryByText('Patrol Applies Safe Fixes and Verifies the Result')).not.toBeInTheDocument(); expect(screen.queryByText('Available now on this instance')).not.toBeInTheDocument(); expect(navigateMock).toHaveBeenCalledWith(SELF_HOSTED_PRO_BILLING_PLAN_HREF, { replace: true, diff --git a/frontend-modern/src/utils/__tests__/licensePresentation.coverage.test.ts b/frontend-modern/src/utils/__tests__/licensePresentation.coverage.test.ts index 17c988055..0f2b146a2 100644 --- a/frontend-modern/src/utils/__tests__/licensePresentation.coverage.test.ts +++ b/frontend-modern/src/utils/__tests__/licensePresentation.coverage.test.ts @@ -520,7 +520,7 @@ describe('getSelfHostedCurrentPlanPresentation - trial branch', () => { upgrade_reasons: [], runtime: { build: 'community', label: 'Pulse Community runtime' }, }, - displayableCapabilities: ['Patrol Handles Safe Fixes'], + displayableCapabilities: ['Patrol Applies Safe Fixes and Verifies the Result'], }); expect(result.title).toBe('Current plan: Pulse Pro Trial'); expect(result.body).toContain('trial entitlement is active'); @@ -581,7 +581,7 @@ describe('getSelfHostedCurrentPlanPresentation - is_lifetime branch', () => { upgrade_reasons: [], runtime: { build: 'pro', label: 'Pulse Pro runtime' }, }, - displayableCapabilities: ['Pulse Relay (Remote Access)', 'Patrol Handles Safe Fixes'], + displayableCapabilities: ['Pulse Relay (Remote Access)', 'Patrol Applies Safe Fixes and Verifies the Result'], }); expect(result.supplementalBadges).toContain('Grandfathered lifetime'); expect(result.supplementalSummary).toContain( @@ -602,7 +602,7 @@ describe('getSelfHostedCurrentPlanPresentation - grace + grandfathered branch', upgrade_reasons: [], runtime: { build: 'pro', label: 'Pulse Pro runtime' }, }, - displayableCapabilities: ['Pulse Relay (Remote Access)', 'Patrol Handles Safe Fixes'], + displayableCapabilities: ['Pulse Relay (Remote Access)', 'Patrol Applies Safe Fixes and Verifies the Result'], }); expect(result.supplementalBadges).toContain('Grandfathered price'); }); @@ -655,7 +655,7 @@ describe('getSelfHostedCurrentPlanPresentation - getPatrolControlAction branches upgrade_reasons: [], runtime: { build: 'pro', label: 'Pulse Pro runtime' }, }, - displayableCapabilities: ['Pulse Relay (Remote Access)', 'Patrol Handles Safe Fixes'], + displayableCapabilities: ['Pulse Relay (Remote Access)', 'Patrol Applies Safe Fixes and Verifies the Result'], patrolOperatorStatus: { patrolControlOperationsLoopStarterCount: 1, patrolControlCompletedOperationsLoopCount: 1, @@ -811,7 +811,7 @@ describe('getSelfHostedActivationSuccessPresentation - purchase + runtime mismat upgrade_reasons: [], runtime: { build: 'community', label: 'Pulse Community runtime' }, }, - displayableCapabilities: ['Pulse Relay (Remote Access)', 'Patrol Handles Safe Fixes'], + displayableCapabilities: ['Pulse Relay (Remote Access)', 'Patrol Applies Safe Fixes and Verifies the Result'], source: 'purchase', }); expect(result).not.toBeNull(); @@ -883,8 +883,8 @@ describe('getSelfHostedActivationSuccessPresentation - highlights dedup', () => runtime: { build: 'pro', label: 'Pulse Pro runtime' }, }, displayableCapabilities: [ - 'Patrol Investigates Issues', - 'Patrol Handles Safe Fixes', + 'Patrol Investigates Issues and Explains the Root Cause', + 'Patrol Applies Safe Fixes and Verifies the Result', '90-day metric history', ], source: 'manual', @@ -892,7 +892,7 @@ describe('getSelfHostedActivationSuccessPresentation - highlights dedup', () => expect(result).not.toBeNull(); const highlights = result?.highlights ?? []; expect(highlights.length).toBe(new Set(highlights).size); - expect(highlights).toContain('Patrol Investigates Issues'); + expect(highlights).toContain('Patrol Investigates Issues and Explains the Root Cause'); expect(highlights).toContain('Role-Based Access Control (RBAC)'); }); }); diff --git a/frontend-modern/src/utils/__tests__/licensePresentation.test.ts b/frontend-modern/src/utils/__tests__/licensePresentation.test.ts index 8608dae20..d1e97e160 100644 --- a/frontend-modern/src/utils/__tests__/licensePresentation.test.ts +++ b/frontend-modern/src/utils/__tests__/licensePresentation.test.ts @@ -335,7 +335,7 @@ describe('licensePresentation', () => { upgrade_reasons: [], runtime: { build: 'pro', label: 'Pulse Pro runtime' }, }, - displayableCapabilities: ['Pulse Relay (Remote Access)', 'Patrol Handles Safe Fixes'], + displayableCapabilities: ['Pulse Relay (Remote Access)', 'Patrol Applies Safe Fixes and Verifies the Result'], }), ).toMatchObject({ title: 'Current plan: Pulse Pro', @@ -357,7 +357,7 @@ describe('licensePresentation', () => { displayableCapabilities: [ 'Pulse Relay (Remote Access)', 'Pulse Mobile Pairing', - 'Patrol Handles Safe Fixes', + 'Patrol Applies Safe Fixes and Verifies the Result', ], }), ).toEqual({ @@ -365,8 +365,8 @@ describe('licensePresentation', () => { body: 'Pulse Pro is active on this instance. It includes Patrol modes (Ask first, Safe auto-fix, Autopilot), 90-day metric history, RBAC, audit logging, reporting, and agent profiles.', unlockedFeaturesLabel: 'Primary capabilities', unlockedFeatures: [ - 'Patrol Investigates Issues', - 'Patrol Handles Safe Fixes', + 'Patrol Investigates Issues and Explains the Root Cause', + 'Patrol Applies Safe Fixes and Verifies the Result', '90-day metric history', ], includedExtrasLabel: 'Included extras', @@ -398,7 +398,7 @@ describe('licensePresentation', () => { displayableCapabilities: [ 'Pulse Relay (Remote Access)', 'Pulse Mobile Pairing', - 'Patrol Handles Safe Fixes', + 'Patrol Applies Safe Fixes and Verifies the Result', ], patrolOperatorStatus: { patrolAutonomyOperationsLoopStarterCount: 1, @@ -429,7 +429,7 @@ describe('licensePresentation', () => { displayableCapabilities: [ 'Pulse Relay (Remote Access)', 'Pulse Mobile Pairing', - 'Patrol Handles Safe Fixes', + 'Patrol Applies Safe Fixes and Verifies the Result', ], patrolOperatorStatus: { proActivationOperationsLoopStarterCount: 1, @@ -458,7 +458,7 @@ describe('licensePresentation', () => { displayableCapabilities: [ 'Pulse Relay (Remote Access)', 'Pulse Mobile Pairing', - 'Patrol Handles Safe Fixes', + 'Patrol Applies Safe Fixes and Verifies the Result', ], patrolOperatorStatus: { patrolControlOperationsLoopStarterCount: 1, @@ -485,7 +485,7 @@ describe('licensePresentation', () => { displayableCapabilities: [ 'Pulse Relay (Remote Access)', 'Pulse Mobile Pairing', - 'Patrol Handles Safe Fixes', + 'Patrol Applies Safe Fixes and Verifies the Result', ], patrolOperatorStatus: { patrolControlOperationsLoopStarterCount: 2, @@ -512,7 +512,7 @@ describe('licensePresentation', () => { displayableCapabilities: [ 'Pulse Relay (Remote Access)', 'Pulse Mobile Pairing', - 'Patrol Handles Safe Fixes', + 'Patrol Applies Safe Fixes and Verifies the Result', ], patrolOperatorStatus: { patrolControlOperationsLoopStarterCount: 1, @@ -544,7 +544,7 @@ describe('licensePresentation', () => { displayableCapabilities: [ 'Pulse Relay (Remote Access)', 'Pulse Mobile Pairing', - 'Patrol Handles Safe Fixes', + 'Patrol Applies Safe Fixes and Verifies the Result', ], patrolOperatorStatus: { patrolAutonomyOperationsLoopStarterCount: 1, @@ -573,7 +573,7 @@ describe('licensePresentation', () => { displayableCapabilities: [ 'Pulse Relay (Remote Access)', 'Pulse Mobile Pairing', - 'Patrol Handles Safe Fixes', + 'Patrol Applies Safe Fixes and Verifies the Result', ], patrolOperatorStatus: { nextAction: 'complete', @@ -602,7 +602,7 @@ describe('licensePresentation', () => { displayableCapabilities: [ 'Pulse Relay (Remote Access)', 'Pulse Mobile Pairing', - 'Patrol Handles Safe Fixes', + 'Patrol Applies Safe Fixes and Verifies the Result', ], patrolOperatorStatus: { nextAction: 'open_mcp', @@ -629,15 +629,15 @@ describe('licensePresentation', () => { upgrade_reasons: [], runtime: { build: 'pro', label: 'Pulse Pro runtime' }, }, - displayableCapabilities: ['Pulse Relay (Remote Access)', 'Patrol Handles Safe Fixes'], + displayableCapabilities: ['Pulse Relay (Remote Access)', 'Patrol Applies Safe Fixes and Verifies the Result'], }), ).toMatchObject({ title: 'Current plan: Legacy Pulse Pro+', body: 'Legacy Pulse Pro+ is active on this instance. It includes Patrol modes (Ask first, Safe auto-fix, Autopilot), 90-day metric history, RBAC, audit logging, reporting, and agent profiles.', unlockedFeaturesLabel: 'Primary capabilities', unlockedFeatures: [ - 'Patrol Investigates Issues', - 'Patrol Handles Safe Fixes', + 'Patrol Investigates Issues and Explains the Root Cause', + 'Patrol Applies Safe Fixes and Verifies the Result', '90-day metric history', ], }); @@ -660,8 +660,8 @@ describe('licensePresentation', () => { body: 'Pulse Pro is active on this instance. It includes Patrol modes (Ask first, Safe auto-fix, Autopilot), 90-day metric history, RBAC, audit logging, reporting, and agent profiles.', unlockedFeaturesLabel: 'Primary capabilities', unlockedFeatures: [ - 'Patrol Investigates Issues', - 'Patrol Handles Safe Fixes', + 'Patrol Investigates Issues and Explains the Root Cause', + 'Patrol Applies Safe Fixes and Verifies the Result', '90-day metric history', ], includedExtrasLabel: 'Included extras', @@ -803,7 +803,7 @@ describe('licensePresentation', () => { upgrade_reasons: [], runtime: { build: 'pro', label: 'Pulse Pro runtime' }, }, - displayableCapabilities: ['Pulse Relay (Remote Access)', 'Patrol Handles Safe Fixes'], + displayableCapabilities: ['Pulse Relay (Remote Access)', 'Patrol Applies Safe Fixes and Verifies the Result'], }).body, ).toBe(getSelfHostedPlanEntitlementSummary('pro', 'Legacy Pulse Pro+')); }); @@ -825,7 +825,7 @@ describe('licensePresentation', () => { upgrade_reasons: [], runtime: { build: 'pro', label: 'Pulse Pro runtime' }, }, - displayableCapabilities: ['Pulse Relay (Remote Access)', 'Patrol Handles Safe Fixes'], + displayableCapabilities: ['Pulse Relay (Remote Access)', 'Patrol Applies Safe Fixes and Verifies the Result'], }).patrolControlAction, ).toEqual(patrolControlAction); @@ -839,7 +839,7 @@ describe('licensePresentation', () => { upgrade_reasons: [], runtime: { build: 'pro', label: 'Pulse Pro runtime' }, }, - displayableCapabilities: ['Patrol Handles Safe Fixes'], + displayableCapabilities: ['Patrol Applies Safe Fixes and Verifies the Result'], }).patrolControlAction, ).toEqual(patrolControlAction); @@ -853,7 +853,7 @@ describe('licensePresentation', () => { upgrade_reasons: [], runtime: { build: 'community', label: 'Pulse Community runtime' }, }, - displayableCapabilities: ['Patrol Handles Safe Fixes'], + displayableCapabilities: ['Patrol Applies Safe Fixes and Verifies the Result'], }).patrolControlAction, ).toBeUndefined(); @@ -870,7 +870,7 @@ describe('licensePresentation', () => { 'Pulse Relay (Remote Access)', 'Pulse Mobile Pairing', 'Push Notifications', - 'Patrol Handles Safe Fixes', + 'Patrol Applies Safe Fixes and Verifies the Result', ], }).patrolControlAction, ).toBeUndefined(); @@ -1234,7 +1234,7 @@ describe('licensePresentation', () => { 'Pulse Relay (Remote Access)', 'Pulse Mobile Pairing', 'Push Notifications', - 'Patrol Handles Safe Fixes', + 'Patrol Applies Safe Fixes and Verifies the Result', ], source: 'purchase', }), @@ -1244,8 +1244,8 @@ describe('licensePresentation', () => { body: 'Checkout completed and Pulse Pro is active. Choose Patrol mode.', highlightsLabel: 'Available now on this instance', highlights: [ - 'Patrol Investigates Issues', - 'Patrol Handles Safe Fixes', + 'Patrol Investigates Issues and Explains the Root Cause', + 'Patrol Applies Safe Fixes and Verifies the Result', '90-day metric history', 'Role-Based Access Control (RBAC)', 'Audit Logging', @@ -1295,7 +1295,7 @@ describe('licensePresentation', () => { limits: [], upgrade_reasons: [], }, - displayableCapabilities: ['Pulse Patrol', 'Patrol Handles Safe Fixes'], + displayableCapabilities: ['Pulse Patrol', 'Patrol Applies Safe Fixes and Verifies the Result'], source: 'purchase', }), ).toBeNull(); @@ -1328,7 +1328,7 @@ describe('licensePresentation', () => { expect( getSelfHostedActivationSuccessPresentation({ entitlements: proEntitlements, - displayableCapabilities: ['Patrol Handles Safe Fixes'], + displayableCapabilities: ['Patrol Applies Safe Fixes and Verifies the Result'], patrolOperatorStatus: { patrolAutonomyOperationsLoopStarterCount: 1, patrolAutonomyCompletedOperationsLoopCount: 0, @@ -1346,7 +1346,7 @@ describe('licensePresentation', () => { expect( getSelfHostedActivationSuccessPresentation({ entitlements: proEntitlements, - displayableCapabilities: ['Patrol Handles Safe Fixes'], + displayableCapabilities: ['Patrol Applies Safe Fixes and Verifies the Result'], patrolOperatorStatus: { proActivationOperationsLoopStarterCount: 1, proActivationCompletedOperationsLoopCount: 0, @@ -1365,7 +1365,7 @@ describe('licensePresentation', () => { expect( getSelfHostedActivationSuccessPresentation({ entitlements: proEntitlements, - displayableCapabilities: ['Patrol Handles Safe Fixes'], + displayableCapabilities: ['Patrol Applies Safe Fixes and Verifies the Result'], patrolOperatorStatus: { patrolControlOperationsLoopStarterCount: 1, proActivationOperationsLoopStarterCount: 1, @@ -1382,7 +1382,7 @@ describe('licensePresentation', () => { expect( getSelfHostedActivationSuccessPresentation({ entitlements: proEntitlements, - displayableCapabilities: ['Patrol Handles Safe Fixes'], + displayableCapabilities: ['Patrol Applies Safe Fixes and Verifies the Result'], patrolOperatorStatus: { nextAction: 'open_mcp', patrolAutonomyOperationsLoopStarterCount: 1, @@ -1402,7 +1402,7 @@ describe('licensePresentation', () => { expect( getSelfHostedActivationSuccessPresentation({ entitlements: proEntitlements, - displayableCapabilities: ['Patrol Handles Safe Fixes'], + displayableCapabilities: ['Patrol Applies Safe Fixes and Verifies the Result'], patrolOperatorStatus: { nextAction: 'complete', patrolAutonomyOperationsLoopStarterCount: 1, @@ -1422,7 +1422,7 @@ describe('licensePresentation', () => { expect( getSelfHostedActivationSuccessPresentation({ entitlements: proEntitlements, - displayableCapabilities: ['Patrol Handles Safe Fixes'], + displayableCapabilities: ['Patrol Applies Safe Fixes and Verifies the Result'], patrolOperatorStatus: { patrolAutonomyOperationsLoopStarterCount: 1, patrolAutonomyCompletedOperationsLoopCount: 1, diff --git a/frontend-modern/src/utils/__tests__/selfHostedPlans.test.ts b/frontend-modern/src/utils/__tests__/selfHostedPlans.test.ts index 07f84d854..9854311d7 100644 --- a/frontend-modern/src/utils/__tests__/selfHostedPlans.test.ts +++ b/frontend-modern/src/utils/__tests__/selfHostedPlans.test.ts @@ -136,8 +136,8 @@ describe('selfHostedPlans', () => { ); expect(SELF_HOSTED_PLAN_BY_TIER.pro.comparisonSummary).not.toContain('how much control'); expect(SELF_HOSTED_PLAN_BY_TIER.pro.entitlementHighlights).toEqual([ - 'Patrol Investigates Issues', - 'Patrol Handles Safe Fixes', + 'Patrol Investigates Issues and Explains the Root Cause', + 'Patrol Applies Safe Fixes and Verifies the Result', '90-day metric history', ]); expect(SELF_HOSTED_PLAN_BY_TIER.pro.includedExtras).toEqual([ diff --git a/frontend-modern/src/utils/selfHostedFeatureCatalog.generated.ts b/frontend-modern/src/utils/selfHostedFeatureCatalog.generated.ts index c0f380f61..1bb3321f0 100644 --- a/frontend-modern/src/utils/selfHostedFeatureCatalog.generated.ts +++ b/frontend-modern/src/utils/selfHostedFeatureCatalog.generated.ts @@ -131,8 +131,8 @@ export const SELF_HOSTED_FEATURE_CATALOG: readonly GeneratedSelfHostedFeatureCat }, { "key": "ai_alerts", - "displayName": "Patrol Investigates Issues", - "comparisonName": "Patrol Investigates Issues", + "displayName": "Patrol Investigates Issues and Explains the Root Cause", + "comparisonName": "Patrol Investigates Issues and Explains the Root Cause", "showInComparisonTable": true, "displayableInSelfHostedPlan": true, "roles": { @@ -148,8 +148,8 @@ export const SELF_HOSTED_FEATURE_CATALOG: readonly GeneratedSelfHostedFeatureCat }, { "key": "ai_autofix", - "displayName": "Patrol Handles Safe Fixes", - "comparisonName": "Patrol Handles Safe Fixes", + "displayName": "Patrol Applies Safe Fixes and Verifies the Result", + "comparisonName": "Patrol Applies Safe Fixes and Verifies the Result", "showInComparisonTable": true, "displayableInSelfHostedPlan": true, "roles": { diff --git a/internal/api/contract_test.go b/internal/api/contract_test.go index 02e750e43..e010a924f 100644 --- a/internal/api/contract_test.go +++ b/internal/api/contract_test.go @@ -7244,7 +7244,7 @@ func TestContract_SelfHostedCommunityEntitlementsJSONSnapshot(t *testing.T) { {"key":"push_notifications","reason":"Get Relay so important alerts reach you immediately on mobile instead of waiting for you to reopen Pulse.","action_url":"https://pulserelay.pro/pricing?utm_source=pulse\u0026utm_medium=app\u0026utm_campaign=upgrade\u0026feature=push_notifications"}, {"key":"relay","reason":"Get Relay so Pulse stays reachable securely from anywhere instead of only on the local dashboard.","action_url":"https://pulserelay.pro/pricing?utm_source=pulse\u0026utm_medium=app\u0026utm_campaign=upgrade\u0026feature=relay"}, {"key":"long_term_metrics","reason":"Get Relay for 14 days of history, or Pro for 90 days, so you can see what changed before and after an incident.","action_url":"https://pulserelay.pro/pricing?utm_source=pulse\u0026utm_medium=app\u0026utm_campaign=upgrade\u0026feature=long_term_metrics"}, - {"key":"ai_autofix","reason":"Upgrade to Pro so Patrol can investigate issues, handle safe fixes within Patrol mode, and verify the outcome.","action_url":"https://pulserelay.pro/pricing?utm_source=pulse\u0026utm_medium=app\u0026utm_campaign=upgrade\u0026feature=ai_autofix"}, + {"key":"ai_autofix","reason":"Upgrade to Pro so Patrol can investigate issues, apply safe fixes within Patrol mode, and verify the result.","action_url":"https://pulserelay.pro/pricing?utm_source=pulse\u0026utm_medium=app\u0026utm_campaign=upgrade\u0026feature=ai_autofix"}, {"key":"ai_alerts","reason":"Upgrade to Pro so Patrol can investigate issues instead of handing you a stack of symptoms.","action_url":"https://pulserelay.pro/pricing?utm_source=pulse\u0026utm_medium=app\u0026utm_campaign=upgrade\u0026feature=ai_alerts"}, {"key":"rbac","reason":"Upgrade to Pro when more than one operator needs safe access boundaries around infrastructure changes.","action_url":"https://pulserelay.pro/pricing?utm_source=pulse\u0026utm_medium=app\u0026utm_campaign=upgrade\u0026feature=rbac"}, {"key":"agent_profiles","reason":"Upgrade to Pro to standardize agent behavior across systems without reconfiguring every install by hand.","action_url":"https://pulserelay.pro/pricing?utm_source=pulse\u0026utm_medium=app\u0026utm_campaign=upgrade\u0026feature=agent_profiles"}, diff --git a/internal/license/coverage_additional_test.go b/internal/license/coverage_additional_test.go index a73dcb6fd..5c45773b1 100644 --- a/internal/license/coverage_additional_test.go +++ b/internal/license/coverage_additional_test.go @@ -78,8 +78,8 @@ func TestGetFeatureDisplayNameCoversKnownFeaturesAndFallback(t *testing.T) { want string }{ {feature: FeatureAIPatrol, want: "Pulse Patrol (Background Health Checks)"}, - {feature: FeatureAIAlerts, want: "Patrol Investigates Issues"}, - {feature: FeatureAIAutoFix, want: "Patrol Handles Safe Fixes"}, + {feature: FeatureAIAlerts, want: "Patrol Investigates Issues and Explains the Root Cause"}, + {feature: FeatureAIAutoFix, want: "Patrol Applies Safe Fixes and Verifies the Result"}, {feature: FeatureKubernetesAI, want: "Kubernetes AI Analysis (Compatibility)"}, {feature: FeatureUpdateAlerts, want: "Update Alerts (Container/Package Updates)"}, {feature: FeatureRBAC, want: "Role-Based Access Control (RBAC)"}, diff --git a/pkg/licensing/features_test.go b/pkg/licensing/features_test.go index 1ef5b36a0..c6359a47d 100644 --- a/pkg/licensing/features_test.go +++ b/pkg/licensing/features_test.go @@ -371,8 +371,8 @@ func TestGetFeatureDisplayName(t *testing.T) { want string }{ {FeatureAIPatrol, "Pulse Patrol (Background Health Checks)"}, - {FeatureAIAlerts, "Patrol Investigates Issues"}, - {FeatureAIAutoFix, "Patrol Handles Safe Fixes"}, + {FeatureAIAlerts, "Patrol Investigates Issues and Explains the Root Cause"}, + {FeatureAIAutoFix, "Patrol Applies Safe Fixes and Verifies the Result"}, {FeatureKubernetesAI, "Kubernetes AI Analysis (Compatibility)"}, {FeatureUpdateAlerts, "Update Alerts (Container/Package Updates)"}, {FeatureRBAC, "Role-Based Access Control (RBAC)"}, diff --git a/pkg/licensing/self_hosted_feature_catalog.go b/pkg/licensing/self_hosted_feature_catalog.go index 0a7106ac8..7f1c10c0f 100644 --- a/pkg/licensing/self_hosted_feature_catalog.go +++ b/pkg/licensing/self_hosted_feature_catalog.go @@ -147,8 +147,8 @@ var featureMetadataCatalog = map[string]FeatureMetadata{ }, FeatureAIAlerts: { Key: FeatureAIAlerts, - DisplayName: "Patrol Investigates Issues", - ComparisonName: "Patrol Investigates Issues", + DisplayName: "Patrol Investigates Issues and Explains the Root Cause", + ComparisonName: "Patrol Investigates Issues and Explains the Root Cause", ShowInComparisonTable: true, DisplayableInPlanUI: true, SelfHostedRoles: SelfHostedFeatureRoles{ @@ -161,8 +161,8 @@ var featureMetadataCatalog = map[string]FeatureMetadata{ }, FeatureAIAutoFix: { Key: FeatureAIAutoFix, - DisplayName: "Patrol Handles Safe Fixes", - ComparisonName: "Patrol Handles Safe Fixes", + DisplayName: "Patrol Applies Safe Fixes and Verifies the Result", + ComparisonName: "Patrol Applies Safe Fixes and Verifies the Result", ShowInComparisonTable: true, DisplayableInPlanUI: true, SelfHostedRoles: SelfHostedFeatureRoles{ @@ -170,7 +170,7 @@ var featureMetadataCatalog = map[string]FeatureMetadata{ Relay: SelfHostedFeatureRoleHidden, Pro: SelfHostedFeatureRolePrimaryPillar, }, - UpgradeReason: "Upgrade to Pro so Patrol can investigate issues, handle safe fixes within Patrol mode, and verify the outcome.", + UpgradeReason: "Upgrade to Pro so Patrol can investigate issues, apply safe fixes within Patrol mode, and verify the result.", UpgradePriority: 3, }, FeatureKubernetesAI: { diff --git a/pkg/licensing/upgrade_test.go b/pkg/licensing/upgrade_test.go index 991db41e5..c5a613e59 100644 --- a/pkg/licensing/upgrade_test.go +++ b/pkg/licensing/upgrade_test.go @@ -96,7 +96,7 @@ func TestOperatorOutcomeUpgradeReasonsRemainCanonical(t *testing.T) { FeatureRelay: "Get Relay so Pulse stays reachable securely from anywhere instead of only on the local dashboard.", FeatureLongTermMetrics: "Get Relay for 14 days of history, or Pro for 90 days, so you can see what changed before and after an incident.", FeatureAIAlerts: "Upgrade to Pro so Patrol can investigate issues instead of handing you a stack of symptoms.", - FeatureAIAutoFix: "Upgrade to Pro so Patrol can investigate issues, handle safe fixes within Patrol mode, and verify the outcome.", + FeatureAIAutoFix: "Upgrade to Pro so Patrol can investigate issues, apply safe fixes within Patrol mode, and verify the result.", } for _, entry := range UpgradeReasonMatrix { diff --git a/tests/integration/tests/55-self-hosted-upgrade-return.spec.ts b/tests/integration/tests/55-self-hosted-upgrade-return.spec.ts index afc6bccdf..5486cfb2b 100644 --- a/tests/integration/tests/55-self-hosted-upgrade-return.spec.ts +++ b/tests/integration/tests/55-self-hosted-upgrade-return.spec.ts @@ -535,7 +535,7 @@ test.describe("Self-hosted upgrade return flow", () => { ), ).toBeVisible(); await expect(activationSummary.getByText("Available now on this instance")).toBeVisible(); - await expect(activationSummary.getByText("Patrol Handles Safe Fixes")).toBeVisible(); + await expect(activationSummary.getByText("Patrol Applies Safe Fixes and Verifies the Result")).toBeVisible(); await expect(page.getByRole("link", { name: "Review usage" })).toHaveCount(0); await expect(page.getByRole("link", { name: "Review plan" })).toHaveCount(0); }); @@ -572,7 +572,7 @@ test.describe("Self-hosted upgrade return flow", () => { page.getByText("Checkout completed and this instance is now running Pulse Pro."), ).toHaveCount(0); await expect(page.getByText("Current plan: Community")).toBeVisible(); - await expect(page.getByText("Patrol Handles Safe Fixes")).toHaveCount(0); + await expect(page.getByText("Patrol Applies Safe Fixes and Verifies the Result")).toHaveCount(0); await expect.poll(() => requestCounts.inactive.entitlements).toBeGreaterThan(0); expect(requestCounts.activated.entitlements).toBe(0); }); @@ -655,7 +655,7 @@ test.describe("Self-hosted upgrade return flow", () => { ), ).toBeVisible(); await expect(activationSummary.getByText("Available now on this instance")).toBeVisible(); - await expect(activationSummary.getByText("Patrol Handles Safe Fixes")).toBeVisible(); + await expect(activationSummary.getByText("Patrol Applies Safe Fixes and Verifies the Result")).toBeVisible(); await expect(page.getByRole("link", { name: "Review plan" })).toHaveCount(0); await expect(page.getByRole("link", { name: "Review usage" })).toHaveCount(0); });