diff --git a/docs/release-control/v6/internal/subsystems/frontend-primitives.md b/docs/release-control/v6/internal/subsystems/frontend-primitives.md
index 990667005..91f80304f 100644
--- a/docs/release-control/v6/internal/subsystems/frontend-primitives.md
+++ b/docs/release-control/v6/internal/subsystems/frontend-primitives.md
@@ -1062,7 +1062,6 @@ and existing alert-history shells instead of introducing VMware-only labels,
badges, or panel copy just because the underlying signal came from vSphere.
That same shared settings and modal boundary now also owns the public usage-data
vocabulary. `frontend-modern/src/components/Settings/GeneralSettingsPanel.tsx`,
-`frontend-modern/src/components/shared/whatsNewModalModel.ts`,
`frontend-modern/src/components/Settings/useSystemSettingsState.ts`, and
`frontend-modern/src/utils/systemSettingsPresentation.ts` must present one
explicit `Usage data and privacy` model centered on `Anonymous outbound
@@ -1725,60 +1724,10 @@ runtime, and `frontend-modern/src/components/shared/searchTipsPopoverModel.ts`
owns trigger variant, label/id defaults, hover policy, and trigger/popover
class selection. Future search-tips work should extend those owners instead of
pushing listener lifecycle or trigger policy back into the shared shell.
-The shared what's-new modal now follows that same owner split.
-`frontend-modern/src/components/shared/WhatsNewModal.tsx` stays the render
-shell, `frontend-modern/src/components/shared/useWhatsNewModalState.ts` owns
-local-storage dismissal, session dismissal, step progression, spotlight target
-resolution, direct stop selection, and overlay placement/runtime behavior, and
-`frontend-modern/src/components/shared/whatsNewModalModel.ts` owns the feature
-tour catalog, telemetry copy, labels, and canonical docs/privacy links. Future
-what's-new work should extend those owners instead of pushing dismissal state,
-spotlight runtime, product copy, or external links back into the shared shell.
-The v6 welcome surface is one guided spotlight tour, not a modal plus a second
-dashboard-only migration hint: it must dim the live app, glow the real
-primary-navigation target being described, and keep route-orientation copy on
-the existing welcome flow instead of layering a duplicate in-product banner.
-Its primary job is fast route orientation. The modal should explain what each
-top-level area is for in plain product language, so operators can understand
-the new navigation in one pass without needing historical layout context.
-That copy should stay direct and present-tense. Each guided step should say
-what the destination does, not depend on v5 comparisons, migration framing, or
-older information architecture to make sense.
-The Infrastructure tour step must describe the source model directly: platform
-API inventory, Pulse Agent telemetry, and discovered candidates are managed as
-infrastructure sources in one place.
-That guided welcome surface should stay compact. The canonical shape is a
-coachmark-sized card centered on the current destination with one short
-step-specific sentence, a small clickable step strip, and minimal footer
-controls. It must not grow back into a large sectioned explainer when one
-sentence would do the job.
-The guided stop map inside that welcome surface is interactive, not decorative:
-operators must be able to jump directly to any tour step from the stop list,
-and desktop layouts may widen the panel enough to keep step labels readable
-without overlapping or collapsing into clipped pills. That map should read as
-numbered wayfinding, not placeholder onboarding chrome: concise numeric badges
-plus section titles are preferred over repeated `Stop N` copy or other filler
-labels that add noise without helping orientation.
-That same welcome surface must stay inside Pulse's existing flat visual
-language. The shell, step map, telemetry note, and supporting actions should
-use bordered flat fills and normal app radii instead of gradient washes,
-glassmorphism, or other marketing-style promo chrome that drifts from the rest
-of the product.
-Secondary disclosures such as telemetry must stay subordinate to that
-orientation job: keep them as footer-level links into the canonical
-privacy/settings surfaces, and do not let them crowd out the migration
-wayfinding copy. The supporting docs CTA on that surface should likewise stay
-route-oriented: use a neutral `Navigation guide` label and plain present-tense
-copy that helps operators understand the current IA, rather than reviving
-`Migration guide` branding that pulls the tour back into v5 historical framing.
-That state owner now also owns public-demo suppression: the modal must stay
-closed until `sessionPresentationPolicyResolved()` is true and must fail closed
-when `presentationPolicyIsDemoMode()` resolves true, so the public demo does
-not front-load product migration onboarding ahead of the actual surface.
-Canonical customer disclosures inside those shared shells now route through
-`frontend-modern/src/utils/docsLinks.ts`, so settings and what's-new privacy
-links resolve to shipped `/docs/...` assets instead of hard-coded GitHub
-`main` URLs that can drift from the running build.
+Canonical customer disclosures inside shared shells route through
+`frontend-modern/src/utils/docsLinks.ts`, so settings privacy links resolve to
+shipped `/docs/...` assets instead of hard-coded GitHub `main` URLs that can
+drift from the running build.
The shared summary strip primitives now follow that same owner split.
`frontend-modern/src/components/shared/SummaryPanel.tsx` and
`frontend-modern/src/components/shared/SummaryMetricCard.tsx` stay the render
diff --git a/docs/release-control/v6/internal/subsystems/registry.json b/docs/release-control/v6/internal/subsystems/registry.json
index 3b38a4ee0..330b3f390 100644
--- a/docs/release-control/v6/internal/subsystems/registry.json
+++ b/docs/release-control/v6/internal/subsystems/registry.json
@@ -3553,7 +3553,6 @@
"frontend-modern/src/components/shared/__tests__/TagBadges.test.tsx",
"frontend-modern/src/components/shared/__tests__/UpgradeLink.test.tsx",
"frontend-modern/src/components/shared/__tests__/WebInterfaceUrlField.test.tsx",
- "frontend-modern/src/components/shared/__tests__/WhatsNewModal.test.tsx",
"frontend-modern/src/components/shared/ColumnPicker.test.tsx",
"frontend-modern/src/components/shared/FilterToolbar.test.tsx",
"frontend-modern/src/components/shared/PageControls.guardrails.test.ts",
diff --git a/docs/release-control/v6/internal/subsystems/security-privacy.md b/docs/release-control/v6/internal/subsystems/security-privacy.md
index 6c16a4a46..de84f5da7 100644
--- a/docs/release-control/v6/internal/subsystems/security-privacy.md
+++ b/docs/release-control/v6/internal/subsystems/security-privacy.md
@@ -315,11 +315,10 @@ abuse controls, `docs/PRIVACY.md` and the shipped
`frontend-modern/public/docs/PRIVACY.md` copy must say so explicitly rather
than implying the server stores nothing at all.
That same rule also applies to the short in-product summary on the shared
-General settings privacy surface and the whats-new disclosure copy. Those
-surfaces may stay concise, but they must not claim a stronger privacy posture
-than the governed docs; if telemetry rows are retained for a fixed window and
-IP addresses are not stored rather than “never seen,” the summary copy must
-say that plainly.
+General settings privacy surface. That surface may stay concise, but it must
+not claim a stronger privacy posture than the governed docs; if telemetry rows
+are retained for a fixed window and IP addresses are not stored rather than
+“never seen,” the summary copy must say that plainly.
That same shared trust boundary now also owns the TLS floor used by pinned-
fingerprint runtime clients. `pkg/tlsutil/fingerprint.go` may support
certificate-fingerprint capture and verification for self-signed deployments,
diff --git a/frontend-modern/src/App.tsx b/frontend-modern/src/App.tsx
index 75636e48f..f13f099a8 100644
--- a/frontend-modern/src/App.tsx
+++ b/frontend-modern/src/App.tsx
@@ -9,7 +9,6 @@ import { logger } from './utils/logger';
import { UpdateBanner } from './components/UpdateBanner';
import { DemoBanner } from './components/DemoBanner';
import { GitHubStarBanner } from './components/GitHubStarBanner';
-import { WhatsNewModal } from './components/shared/WhatsNewModal';
import { KeyboardShortcutsModal } from './components/shared/KeyboardShortcutsModal';
import { CommandPaletteModal } from './components/shared/CommandPaletteModal';
import { dialogStackHasBlockingDialog } from './components/shared/useDialogState';
@@ -379,7 +378,6 @@ function App() {
-
{/* Main layout container - flexbox to allow AI panel to push content */}
diff --git a/frontend-modern/src/components/Settings/GeneralSettingsPanel.tsx b/frontend-modern/src/components/Settings/GeneralSettingsPanel.tsx
index d1ddcec7f..9582b8eb8 100644
--- a/frontend-modern/src/components/Settings/GeneralSettingsPanel.tsx
+++ b/frontend-modern/src/components/Settings/GeneralSettingsPanel.tsx
@@ -9,10 +9,8 @@ import Sun from 'lucide-solid/icons/sun';
import Moon from 'lucide-solid/icons/moon';
import Thermometer from 'lucide-solid/icons/thermometer';
import Maximize2 from 'lucide-solid/icons/maximize-2';
-import Compass from 'lucide-solid/icons/compass';
import { temperatureStore } from '@/utils/temperature';
import { layoutStore } from '@/utils/layout';
-import { WHATS_NEW_REOPEN_EVENT } from '@/components/shared/whatsNewModalModel';
import {
PVE_POLLING_MAX_SECONDS,
PVE_POLLING_MIN_SECONDS,
@@ -167,31 +165,6 @@ export const GeneralSettingsPanel: Component = (props
onChange={() => layoutStore.toggle()}
/>
-
- {/* Reopen Navigation Guide */}
-
-
-
-
-
-
-
Navigation guide
-
- Replay the four-stop walkthrough of Infrastructure, Workloads, Storage, and
- Recovery.
-
-
-
-
-
{/* Usage Data + Privacy Card */}
diff --git a/frontend-modern/src/components/shared/SharedPrimitives.guardrails.test.ts b/frontend-modern/src/components/shared/SharedPrimitives.guardrails.test.ts
index 4dc5f08ab..a5f111e44 100644
--- a/frontend-modern/src/components/shared/SharedPrimitives.guardrails.test.ts
+++ b/frontend-modern/src/components/shared/SharedPrimitives.guardrails.test.ts
@@ -36,8 +36,6 @@ import infrastructureSelectorSource from '@/components/shared/InfrastructureSele
import pulseDataGridSource from '@/components/shared/PulseDataGrid.tsx?raw';
import pulseDataGridModelSource from '@/components/shared/pulseDataGridModel.ts?raw';
import progressBarSource from '@/components/shared/ProgressBar.tsx?raw';
-import whatsNewModalSource from '@/components/shared/WhatsNewModal.tsx?raw';
-import whatsNewModalModelSource from '@/components/shared/whatsNewModalModel.ts?raw';
import searchFieldSource from '@/components/shared/SearchField.tsx?raw';
import searchFieldModelSource from '@/components/shared/searchFieldModel.ts?raw';
import searchInputSource from '@/components/shared/SearchInput.tsx?raw';
@@ -102,7 +100,6 @@ import infrastructureDetailsDrawerStateSource from '@/components/shared/useInfra
import mobileNavBarStateSource from '@/components/shared/useMobileNavBarState.ts?raw';
import infrastructureSelectorStateSource from '@/components/shared/useInfrastructureSelectorState.ts?raw';
import pulseDataGridStateSource from '@/components/shared/usePulseDataGridState.ts?raw';
-import whatsNewModalStateSource from '@/components/shared/useWhatsNewModalState.ts?raw';
import searchFieldStateSource from '@/components/shared/useSearchFieldState.ts?raw';
import searchInputStateSource from '@/components/shared/useSearchInputState.ts?raw';
import searchInputEnhancementsStateSource from '@/components/shared/useSearchInputEnhancements.ts?raw';
@@ -1309,39 +1306,6 @@ describe('shared primitive guardrails', () => {
expect(searchTipsPopoverModelSource).toContain('shouldSearchTipsPopoverOpenOnHover');
});
- it('keeps whats new modal on shell, runtime, and model owners', () => {
- expect(whatsNewModalSource).toContain('useWhatsNewModalState');
- expect(whatsNewModalSource).toContain('useDialogState');
- expect(whatsNewModalSource).toContain('WHATS_NEW_FEATURE_CARDS');
- expect(whatsNewModalSource).toContain('Portal');
- expect(whatsNewModalSource).not.toContain('createLocalStorageBooleanSignal');
- expect(whatsNewModalSource).not.toContain('createSignal');
- expect(whatsNewModalSource).not.toContain('WHATS_NEW_NAV_V2_SHOWN');
- expect(whatsNewModalSource).not.toContain('Migration guide');
- expect(whatsNewModalSource).not.toContain(
- 'https://github.com/rcourtman/Pulse/blob/main/docs/PRIVACY.md',
- );
-
- expect(whatsNewModalStateSource).toContain('export function useWhatsNewModalState');
- expect(whatsNewModalStateSource).toContain('createLocalStorageBooleanSignal');
- expect(whatsNewModalStateSource).toContain('createSignal');
- expect(whatsNewModalStateSource).toContain('createMemo');
- expect(whatsNewModalStateSource).toContain('STORAGE_KEYS.WHATS_NEW_NAV_V2_SHOWN');
- expect(whatsNewModalStateSource).toContain('sessionPresentationPolicyResolved');
- expect(whatsNewModalStateSource).toContain('presentationPolicyIsDemoMode');
- expect(whatsNewModalStateSource).toContain('handleClose');
- expect(whatsNewModalStateSource).toContain('handleNext');
- expect(whatsNewModalStateSource).toContain('spotlightStyle');
-
- expect(whatsNewModalModelSource).toContain('WHATS_NEW_FEATURE_CARDS');
- expect(whatsNewModalModelSource).toContain('WHATS_NEW_DOCS_URL');
- expect(whatsNewModalModelSource).toContain('WHATS_NEW_PRIVACY_URL');
- expect(whatsNewModalModelSource).toContain('WHATS_NEW_DOCS_LABEL');
- expect(whatsNewModalModelSource).toContain('MIGRATION_GUIDE_DOC_URL');
- expect(whatsNewModalModelSource).toContain('Telemetry details');
- expect(whatsNewModalModelSource).toContain("title: 'Infrastructure'");
- });
-
it('keeps dialog stack visibility in the shared dialog runtime', () => {
expect(dialogStateSource).toContain('export function dialogStackHasBlockingDialog');
expect(dialogStateSource).toContain('createSignal');
diff --git a/frontend-modern/src/components/shared/WhatsNewModal.tsx b/frontend-modern/src/components/shared/WhatsNewModal.tsx
deleted file mode 100644
index fc9fa0f80..000000000
--- a/frontend-modern/src/components/shared/WhatsNewModal.tsx
+++ /dev/null
@@ -1,195 +0,0 @@
-import { For, Show } from 'solid-js';
-import { Portal } from 'solid-js/web';
-import ServerIcon from 'lucide-solid/icons/server';
-import BoxesIcon from 'lucide-solid/icons/boxes';
-import HardDriveIcon from 'lucide-solid/icons/hard-drive';
-import ShieldCheckIcon from 'lucide-solid/icons/shield-check';
-import XIcon from 'lucide-solid/icons/x';
-import {
- WHATS_NEW_BACK_LABEL,
- WHATS_NEW_CLOSE_LABEL,
- WHATS_NEW_DOCS_LABEL,
- WHATS_NEW_DOCS_URL,
- WHATS_NEW_DO_NOT_SHOW_LABEL,
- WHATS_NEW_FEATURE_CARDS,
- WHATS_NEW_KICKER_LABEL,
- WHATS_NEW_NEXT_LABEL,
- WHATS_NEW_PRIMARY_ACTION_LABEL,
- WHATS_NEW_PROGRESS_PREFIX,
- WHATS_NEW_PRIVACY_URL,
- WHATS_NEW_TELEMETRY_LINK_LABEL,
- WHATS_NEW_TITLE,
- type WhatsNewFeatureCard,
-} from './whatsNewModalModel';
-import { useDialogState } from './useDialogState';
-import { useWhatsNewModalState } from './useWhatsNewModalState';
-
-function WhatsNewFeatureIcon(props: { card: WhatsNewFeatureCard }) {
- switch (props.card.icon) {
- case 'infrastructure':
- return ;
- case 'workloads':
- return ;
- case 'storage':
- return ;
- case 'recovery':
- return ;
- }
-}
-
-export function WhatsNewModal() {
- const state = useWhatsNewModalState();
- const dialogState = useDialogState({
- get isOpen() {
- return state.isOpen();
- },
- onClose: state.handleClose,
- });
- const step = () => state.currentStep();
- const setPanelRef = (element: HTMLDivElement) => {
- state.setPanelRef(element);
- dialogState.setPanelRef(element);
- };
-
- return (
-
-
-