# Design ## Context See proposal.md — Why. The `fpagent-installer` capability (change `fpagent-release-installer`) installs the newest release and hands off to the bundle's `deploy/install.sh`, which replaces the binary but only warns when a daemon is running. The bundle name already embeds the git hash (`fpagent--.tar.gz`) and `bundle.sh` already builds the binary with that hash as its embedded `Version`. ## Goals / Non-Goals **Goals:** install a pinned release; make a rerun a real upgrade that reports what changed and takes effect; keep both install paths (hosted and direct bundle) consistent. **Non-Goals:** a separate version service or a new `--version` CLI flag; signing or provenance beyond sha256; a downgrade-unsafe rollback. ## Decisions 1. **The version is the asset-name git hash.** It is already the binary's embedded `Version` and needs no new endpoint or flag. The hosted installer parses it, and also writes it as `VERSION` in the extracted bundle so the bundle installer has it even for bundles built before this change. 2. **The bundle installer owns the upgrade reporting and the restart.** It knows `INSTALL_PATH` and the service; the hosted installer only fetches, verifies and hands off. `bundle.sh` ships `VERSION` so direct bundle installs behave the same. The stamp lives at `${INSTALL_PATH}.version`, so a custom `--install-path` keeps its own record, and uninstall removes it. 3. **Restart only on a managed, already-running service.** `enable --now` starts a stopped unit; for an upgrade the installer checks `is-active` before enabling and restarts only if it was active, avoiding a redundant restart on a fresh install. 4. **`--tag` reuses the release handler.** A second same-origin metadata route (`/fpagent/releases/tags/:tag`) shares the latest route's handler, so the filtering and non-disclosure rules are identical; the installer switches only the metadata URL, then downloads by the resolved tag. ## Risks / Trade-offs - [Bundles built before this change carry no VERSION and do not restart] → the hosted installer writes VERSION from the asset name (fixes reporting), but the restart is in the bundle and appears only after a new `fingerprint-agent` release. Until then upgrades still need a manual restart. - [Upgrade without `--enable-service` leaves a running daemon on the old binary] → the installer warns; the documented install command uses `--enable-service`. - [A pinned tag whose assets differ] → the tag's own metadata drives asset selection, the same as latest. ## Migration Plan Release a new `fingerprint-agent` bundle (ships VERSION and restarts on upgrade), then deploy the app. The hosted installer is backward compatible: with an older bundle it reports the version but the bundle's older installer ignores the stamp. Rollback = revert the app; `--tag` can pin the previous release. ## Open Questions None.