aim/.plans/003-remove-uninstall-metadata/2026-03-19-remove-uninstall-metadata-design.md

5.2 KiB

Remove Uninstall Metadata Design

Goal

Make aim remove uninstall aim-managed app artifacts rather than only unregistering apps, while preserving backward compatibility for existing registry entries and keeping uninstall logic in aim-core.

Agreed Product Shape

Remove behavior

  • aim remove <QUERY> should delete the tracked app from the registry
  • It should also remove aim-managed installed artifacts for that app
  • Missing artifact files should not make removal fail
  • Desktop refresh helper failures should surface as warnings rather than block removal

Metadata model

  • Persist install metadata on successful install
  • Persist exact installed paths for payload, desktop entry, and icon
  • Persist the effective install scope
  • Keep install metadata optional so old registry entries still deserialize cleanly

Compatibility posture

  • New installs should uninstall using persisted exact paths
  • Existing registry entries without install metadata should fall back to derived aim-managed paths
  • Uninstall should only target paths that belong to aim management, not arbitrary external files

Use a hybrid uninstall model.

This combines exact persisted install metadata for newly installed apps with a conservative derived-path fallback for legacy registry entries. It avoids breaking older registries while making future uninstall behavior precise and resilient to layout changes.

The model is:

  • successful install persists InstallMetadata into AppRecord
  • remove resolves uninstall targets from metadata when present
  • remove falls back to aim-managed path derivation when metadata is absent
  • uninstall deletes payload, desktop entry, and icon, then refreshes desktop caches best-effort

Data Model

InstallMetadata

Persist this on each installed app record:

  • scope
  • payload_path
  • desktop_entry_path
  • icon_path

Store these as optional path strings under an optional install field on AppRecord.

Backward compatibility

  • AppRecord.install is optional
  • legacy records continue to load unchanged
  • remove derives fallback targets from stable_id and inferred scope when install is absent

Remove Execution Model

1. Resolve the app

  • Match the registered app by stable id or display name
  • Preserve existing ambiguity behavior

2. Resolve uninstall targets

Prefer persisted metadata:

  • exact payload path
  • exact desktop entry path
  • exact icon path
  • persisted scope

Fallback for legacy records:

  • payload path from managed_appimage_path(...)
  • desktop entry path from desktop_entry_path(...)
  • icon path from icon_path(...)
  • scope inferred conservatively, defaulting to user-managed locations when exact scope is unknown

3. Delete managed artifacts

Delete only aim-managed artifacts:

  • AppImage payload
  • generated .desktop file
  • generated icon

Rules:

  • treat missing files as already removed
  • collect deleted paths for reporting
  • do not attempt to delete non-aim unmanaged locations

4. Refresh desktop integration best-effort

  • probe helpers using the same capability model used by install
  • run update-desktop-database and gtk-update-icon-cache when relevant
  • return warnings instead of failing removal if refresh helpers are missing or fail

5. Persist registry last

  • only save the registry after uninstall execution completes
  • successful uninstall with warnings still removes the registry entry

Safety Model

Managed-only deletion

Uninstall must only delete files that are known aim outputs:

  • persisted metadata generated by aim
  • derived managed paths under aim-controlled naming conventions

Idempotency

Repeated remove attempts should be safe:

  • missing files are ignored
  • warnings can still be emitted for helper refresh failures
  • registry result remains correct even if artifacts were already manually deleted

Failure handling

  • file deletion failures should stop removal and keep the app registered
  • refresh failures should not block removal
  • no rollback is needed for already-deleted files

Verification Strategy

Unit tests

  • install metadata round-trips through the registry model
  • remove plan resolves exact persisted paths
  • remove plan falls back to derived managed paths for legacy records

Integration tests

  • add then remove deletes payload, desktop entry, and icon
  • remove tolerates already-missing artifacts
  • remove emits warnings when refresh helpers are unavailable or fail
  • legacy registry entries without install metadata still uninstall derived user-managed files

Architecture Slice

Core changes

  • extend domain::app::AppRecord with optional InstallMetadata
  • populate InstallMetadata in the add/install path from InstalledApp
  • extend app::remove with uninstall planning and execution
  • reuse integration::refresh helper execution after deletion

CLI changes

  • keep CLI thin
  • aim-cli should continue delegating uninstall behavior to aim-core
  • render warnings from uninstall results if present

Non-Goals

  • deleting arbitrary external files not managed by aim
  • adding a separate garbage collection command in this change
  • refactoring install path layout beyond the metadata needed for uninstall