5.2 KiB
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
- Delivery.
sudo make installbuilds a wheel from the checkout and installs it, with pinned dependencies, into a dedicated Fenris-owned venv at/opt/fenris; a/usr/local/bin/fenriswrapper makes the unprivileged TUI/CLI a PATH command. The checkout is build-time input only: after install, nothing references it. - 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. - Privilege. One root installer (
sudo make install); at runtime, elevation is exclusively polkit (auth_admin,fenris-monitoronly, ADR 0003). The installer never enables or starts units. - 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. - Legacy import. The installer detects
./data/history.jsonlbeside 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. - Upgrade.
sudo make upgradebuilds 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 withPersistent=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 aschema_versiontable./var/lib/fenrisis never rebuilt. - Rollback. Best-effort by design: before migrations run, the installer snapshots
observations.dbto a one-generationobservations.db.bak; rollback means reinstalling the previous version and restoring the backup. Automatic schema downgrade is explicitly unsupported. - Removal.
make uninstallfirst performs the sanctioned disable (fenris-monitor disable --now) so an open monitoring period closesuser_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/fenrisand the observation store.make purgeadditionally removes configuration and store. Journal entries age out naturally. - 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. - Scaffolding and floor. The installer creates
/var/lib/fenriswith ADR 0001's root-written group-read permissions and verifiespython3 ≥ 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.