mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-09-10 02:25:56 +00:00
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.
This commit is contained in:
@@ -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) | ✅ | ✅ | ✅ | ✅ |
|
||||
|
||||
+2
-2
@@ -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]`. |
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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)');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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([
|
||||
|
||||
@@ -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": {
|
||||
|
||||
@@ -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"},
|
||||
|
||||
@@ -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)"},
|
||||
|
||||
@@ -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)"},
|
||||
|
||||
@@ -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: {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user