Files
Fenris/docs/adr/0004-install-upgrade-removal-lifecycle.md

5.2 KiB

4. Installation lifecycle: Makefile-delivered venv, dormant install, sanctioned teardown

Status

Accepted — resolves Define installation, upgrade, and removal behavior on the Wayfinder map.

Context

Fenris runs today from the source checkout (fenris.py, fenris.sh, data/): code, state, and control all live relative to wherever the checkout sits. The redesign fixes system artifacts — helpers in /usr/libexec/fenris (ADR 0003), the observation store at /var/lib/fenris/observations.db (ADR 0001), configuration at /etc/fenris/fenris.conf (ADR 0003), Textual on Python 3.9+ (framework decision) — but nothing says how those artifacts are delivered, upgraded, or removed, or what happens when the checkout moves or disappears.

Decision

  1. Delivery. sudo make install builds a wheel from the checkout and installs it, with pinned dependencies, into a dedicated Fenris-owned venv at /opt/fenris; a /usr/local/bin/fenris wrapper makes the unprivileged TUI/CLI a PATH command. The checkout is build-time input only: after install, nothing references it.
  2. Layout and manifest. Units in /etc/systemd/system (fenris-collect.{timer,service}, ADR 0003); helpers in /usr/libexec/fenris; polkit policy in /usr/share/polkit-1/actions/; configuration and observation store in their ADR-fixed locations. The installer records every file it places in an explicit manifest consumed by upgrade and uninstall.
  3. Privilege. One root installer (sudo make install); at runtime, elevation is exclusively polkit (auth_admin, fenris-monitor only, ADR 0003). The installer never enables or starts units.
  4. Dormant install. A fresh install is fully dormant: units present but disabled, nothing running, no monitoring period. The only opt-in is the sanctioned toggle (fenris monitor resume [--now], or the first-run TUI prompt), which enables the timer and opens the first period in one step.
  5. Legacy import. The installer detects ./data/history.jsonl beside the source (or accepts an explicit path), runs ADR 0001's idempotent single-transaction import, and reports imported counts — existing observations never depend on checkout survival. fenris import <path> remains available for later finds.
  6. Upgrade. sudo make upgrade builds and installs the new wheel into the same venv, syncs units and polkit against the manifest (daemon-reload; restart the timer only if unit contents changed and it is active — safe with Persistent=no), leaves timer state untouched, and never kills an in-flight collection run: a running oneshot finishes on its mapped interpreter, so at worst one old-code run completes to the store and the next run uses the new code. It then applies forward-only observation-store schema migrations governed by a schema_version table. /var/lib/fenris is never rebuilt.
  7. Rollback. Best-effort by design: before migrations run, the installer snapshots observations.db to a one-generation observations.db.bak; rollback means reinstalling the previous version and restoring the backup. Automatic schema downgrade is explicitly unsupported.
  8. Removal. make uninstall first performs the sanctioned disable (fenris-monitor disable --now) so an open monitoring period closes user_disabled — removal is deliberate, and only the sanctioned path records intent — then stops and disables the units and removes the venv, helpers, units, polkit policy, and wrapper, keeping /etc/fenris and the observation store. make purge additionally removes configuration and store. Journal entries age out naturally.
  9. Dependencies. Exact pins in a committed lockfile; install and upgrade both install from it. Refreshing pins is an explicit developer step (make update-deps, committed), never a side effect of installing.
  10. Scaffolding and floor. The installer creates /var/lib/fenris with ADR 0001's root-written group-read permissions and verifies python3 ≥ 3.9, failing cleanly otherwise — the Textual contingency becomes an install-time gate rather than a runtime crash. The database file itself is created lazily by the first write, so "no observations yet" remains a real state the TUI can greet.

Consequences

  • Installed Fenris survives checkout deletion; the checkout is only where builds happen.
  • Teardown preserves monitoring-period semantics: deliberate removal excludes the uninstalled span from the usage habit instead of leaving it as unknown-inside.
  • Installs are reproducible; dependency drift cannot ride in on an upgrade.
  • Reinstall after uninstall resumes from the preserved observation store; only purge erases history.
  • Rollback support is exactly one generation deep, no further.
  • The README documents install, upgrade, uninstall/purge, and legacy import alongside ADR 0003's menu-successor mapping.