Skip to content

Add persistent profile rename and deletion controls #45

Description

@Andresshamis

Meridian Explorer automation, posting through @Andresshamis.

Priority: P2
Type: privacy / feature / product / accessibility / testing / architecture
Ready status: ready

Problem statement

Meridian now supports creating and switching persistent profiles, but it does not expose persistent profile rename or deletion controls. The missing deletion path is privacy-sensitive because persistent profiles carry app-state records, profile-scoped local history, site permission settings, tabs/spaces/folders/split metadata, and a stable WKWebsiteDataStore identifier. Without a deliberate lifecycle contract, PR Agent work could later add profile removal in the UI without clearing all dependent state or without documenting WebKit cleanup limits.

Why it matters for Meridian

Profiles are both a primary workflow primitive and a privacy boundary. Users need to correct profile names and remove profiles they no longer want, while Meridian must make deletion semantics explicit: removing a profile should remove Meridian-owned state for that profile, avoid selecting stale IDs, and clear or conservatively document profile-scoped WebKit website data behavior. This keeps profile management aligned with the product mission and prevents profile-isolation work from becoming internal-only infrastructure.

Evidence

  • Closed issue Add persistent profile creation and switching controls #29 and merged PR Add persistent profile creation and switching controls #32 intentionally covered only persistent profile creation/switching; issue Add persistent profile creation and switching controls #29's proposed direction said to avoid rename/delete/import/export in that first slice.
  • Docs/FeatureChecklist.md still lists Profile rename/delete/import/export controls under Not Yet Implemented.
  • Sources/MeridianCore/Stores/BrowserStore.swift exposes createProfile(name:ephemeral:), createPersistentProfile(name:), and switchProfile(_:), but repo search found no renameProfile, deleteProfile, removeProfile, or profile-dependent cleanup API.
  • Sources/MeridianCore/Views/Sidebar/SidebarView.swift and Sources/MeridianBrowser/MeridianBrowserApp.swift expose persistent profile creation/switching menus, but no rename/delete commands.
  • Sources/MeridianCore/WebKit/ProfileWebsiteDataStoreProvider.swift creates persistent stores through WKWebsiteDataStore(forIdentifier:), but there is no profile deletion cleanup service or documented fallback for website data that belongs to a removed profile.
  • BrowserStore.persistentSnapshot(...) and local-history persistence filter private profiles, but there is no test that deleting a persistent profile removes its public dependent state from session/history persistence.

Affected files/components

  • Sources/MeridianCore/Models/BrowserProfile.swift
  • Sources/MeridianCore/Stores/BrowserStore.swift
  • Sources/MeridianCore/WebKit/ProfileWebsiteDataStoreProvider.swift
  • Sources/MeridianCore/Services/LocalHistoryStore.swift
  • Sources/MeridianCore/Services/LocalHistoryPersistenceBoundary.swift
  • Sources/MeridianCore/Services/SessionPersistenceBoundary.swift
  • Sources/MeridianCore/Views/Sidebar/SidebarView.swift
  • Sources/MeridianBrowser/MeridianBrowserApp.swift
  • Sources/MeridianCore/Views/CommandBar/CommandBarView.swift
  • Sources/MeridianCore/Services/CommandRouter.swift
  • Tests/MeridianBrowserTests/BrowserStoreTests.swift
  • Tests/MeridianBrowserTests/ProfileMetadataTests.swift
  • Docs/FeatureChecklist.md
  • Docs/ThreatModel.md
  • Docs/TestPlan.md
  • Docs/WebKitLimitations.md

Expected behavior

A user can rename a persistent profile and delete a persistent profile through accessible native UI. Deleting a profile removes Meridian-owned state for that profile, clears profile-scoped local history and site permission settings, removes dependent spaces/folders/tabs/split views/selected IDs from persistence, selects a safe fallback persistent context, and handles the profile's WKWebsiteDataStore data according to the safest supported WebKit behavior.

Proposed direction

Add a focused persistent-profile lifecycle slice after the creation/switching baseline. PR Agent should branch from origin/dev and target dev.

Recommended scope:

  • add BrowserStore.renamePersistentProfile(...) with trimmed-name/default-name handling and persistence;
  • add BrowserStore.deletePersistentProfile(...) or equivalent that rejects deleting the last persistent profile unless it first creates/selects a safe replacement;
  • remove dependent spaces, folders, tabs, split layouts, selected IDs, local history entries, and site permission settings for the deleted profile;
  • select an existing persistent profile/space/tab fallback, or seed the default public context when needed;
  • add sidebar/profile-menu and native-menu controls with confirmation copy that does not expose URLs or private data;
  • introduce a small WebKit/profile-data cleanup boundary that can call the supported WKWebsiteDataStore removal API for the profile's identified store where practical, and document any API limitation instead of faking deletion;
  • keep import/export out of this issue unless needed for a tiny internal helper.

Acceptance criteria

  • Persistent profiles can be renamed from a visible UI path and at least one keyboard-accessible/native path.
  • Profile rename trims blank input, preserves a safe non-empty name, persists across session save/load, and does not affect private-profile behavior.
  • Persistent profiles can be deleted only after an explicit confirmation step.
  • Deleting a persistent profile removes its dependent spaces, folders, tabs, split layouts, selected IDs, profile-scoped local history entries, and site permission settings from runtime state.
  • Deleting the active profile selects an existing persistent fallback profile/space/tab, or creates a safe public default if no fallback remains.
  • Deleting a non-active profile does not disturb the active persistent profile except for removing stale references to the deleted profile.
  • The raw SQLite session and local-history payloads no longer include the deleted profile ID, profile-scoped history, site permission origins, tab URLs, or restoration metadata after deletion and save.
  • WebKit website data cleanup for the deleted profile is routed through a dedicated boundary; if public WebKit APIs cannot prove full cleanup for identified stores in unit tests, the limitation is documented and a Implement persistence and profile isolation verification #3/Add Xcode app project and UI test host #4 fixture follow-up is named.
  • Private/ephemeral profiles remain excluded from persistent profile rename/delete surfaces; private-session deletion stays with issue Add private browsing session lifecycle controls #43.
  • Docs and test plan describe persistent profile lifecycle semantics and distinguish app-state deletion from runtime WebKit isolation fixture proof.

Dependencies/blockers

Suggested tests

  • BrowserStoreTests for renaming a persistent profile and saving/restoring the updated name.
  • BrowserStoreTests for deleting inactive and active persistent profiles, including dependent spaces/folders/tabs/split views/selected IDs cleanup.
  • Persistence tests proving raw SQLite session bytes and local-history payloads omit the deleted profile ID and deleted profile URLs after save.
  • Site-permission tests proving deleted-profile settings are removed and do not satisfy another profile's requests.
  • Local-history tests proving profile deletion clears only that profile's entries.
  • Tests proving private/ephemeral profiles are not offered through persistent rename/delete surfaces.
  • Future UI/WebKit fixture after issue Add Xcode app project and UI test host #4 proving deleting a profile clears or isolates cookies/localStorage for that profile's identified WebKit data store.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions