# Public application update owner The public profile updates the backend, dashboard and their packaged runtime helpers. It does not run a Debian/kernel transaction. The original root-signed manifest must authorize `application_update: {version: 2, mode: "signed-application-runtime"}` and exactly the backend/frontend component pair. Existing or partial D09/C01 ownership always selects its protected admission route; missing managed file descriptors or failed transport cannot authorize a public fallback. The earlier version 1 pair-only policy remains recognized for compatibility and focused transaction qualification. ## Transaction boundary The installed root-owned verifier authenticates the original signed JSON. Root preparation copies the authenticated downloads into immutable snapshots, then submission installs the current owner's embedded Python as an independent PID1 worker. Its journal and snapshots live below `/var/lib/archipelago-public-transactions`. The manager's response acknowledges submission; it does not acknowledge successful installation. Before replacement the worker verifies the running manager, stops it, drains maintenance timers, freezes both code preimages and the fixed runtime domain listed in `scripts/public_update_runtime.py`, and records their identities. The domain contains application code, radio helpers, relevant systemd units, existing nginx routing, and the public-runtime ownership record. Optional kiosk, audio and gamepad helpers remain absent when the previous installation omitted them. The worker preserves service enablement decisions and restores only timers that were already active. An in-flight maintenance job refuses the attempt. The incoming dashboard retains the existing validated nginx routing template. A root-owned record binds the executing backend hash and release version to the transaction. On that startup, the backend skips the older nontransactional host runtime promotion and repair routines. Normal application startup, container reconciliation and API behavior continue after the code owner releases startup. All code mutation follows durable preparation. Boot recovery is durably linked before the transaction becomes current. It restores interrupted transactions before the manager, doctor and NPM maintenance units can start. A submission interrupted before publishing its pointer can recover only while its original predecessor remains the current completed transaction. Old recovery units cannot operate on a newer transaction. Retried upgrades after rollback reuse only the previous owner's exact known service dependencies. Every forward or reverse replacement checks the complete installed and saved identity domains; foreign edits and corrupt preimages are retained for reconciliation. Success requires the actual `/proc/PID/exe` hash, backend health/version, exact served frontend entry bytes, and exact installed code/runtime identities. Recovery is resumable and must verify the old running pair before reporting `restored`. The manager namespace hides the frontend's runtime bootstrap input after a runtime transaction. This prevents an authenticated historical binary from repromoting that payload on rollback and deleting restored private app sources. The host owner and nginx retain the complete authenticated frontend. A durable transaction marker also holds maintenance services and timers while startup is being verified. If the historical binary re-enables a previously disabled timer, recovery removes only its exact standard enablement link before releasing the pause; foreign links remain a reconciliation error. No worker destination is a wallet, container store, app data directory or install/uninstall/stopped record. The application prefix directory itself gains root custody so an application cannot rename installation paths; this does not recursively change ownership of its children or data. Original downloads, retired trees and failures remain available; there is no evidence garbage collection. ## First upgrade from a historical installer An older updater such as 1.9.1 replaces its code pair, writes the pending verification marker, deletes staging, then restarts the newly installed daemon. The successor handles that marker before host bootstrap or application recovery. It remains in `Type=notify` startup, extending the bounded startup timeout while an independent root operation admits the migration. That operation fetches `manifest.json` and `legacy-manifest-VERSION.json` from the successor's fixed HTTPS release attachment origin. Both original documents must verify under the pinned release root. It fetches the signed incoming artifacts again because historical staging no longer exists. The historical backend backup must match its old signed artifact; the frontend backup must match its signed archive, allowing only the documented existing routing-template mutation and Companion bytes already present in the signed incoming release. Signed old static extras are preserved when the new archive does not supersede them. Arbitrary backup scripts are never accepted as executable recovery input. The installed incoming pair is checked against those authenticated images before queuing the same runtime transaction. Its frozen old pair can be restored even if the worker dies before runtime preparation. The exact pending marker is retained inside the transaction on completion or recovery. A changed marker is not deleted. Interruption before the independent owner has admitted the upgrade still belongs to the historical installer's recovery behavior; that limitation must be tested with the actual older artifact, not inferred from worker fixtures. The new installed binary is already the older authenticated installer's chosen executable. This startup handoff is distinct from executing an uninstalled candidate to establish its own verification authority. Publication uses a separate appointed verifier and clean build receipt. ## Protected and custom installations The fixed public layout is `/usr/local/bin/archipelago`, `/opt/archipelago/web-ui`, `User=archipelago`, no extra ExecStart arguments, backend port 5678 and dashboard port 80. Custom layouts, special preimage inodes and unresolved foreign ownership refuse conversion. Protected nodes retain their release-bound D09/OS plans and admission; a generic public manifest does not replace that authorization. A source bundle can also be emitted with `python3 scripts/package-public-update-worker.py --output /new/output/worker.py`. This creates no installation or authority. A separately reviewed root-custody installation is required before an older client without the successor's dispatch can invoke its fixed `apply` command with original signed JSON on stdin. No frontend-downloaded bundle is automatically executed as root. Status and manual recovery stay available through the independent retained worker after rollback. ## Qualification The PID1 fixture uses a private disconnected container store without host mounts. It retains each frozen attempt, journal and transaction. It has explicit fixture ELF, signature and download doubles, and exercises real service replacement, runtime files, startup handoff, crash boundaries and a full PID1 restart. These results do not qualify a production signature, actual product startup, public availability or physical acceptance. Those gates require their own evidence. Backend tests run through `scripts/test-backend-isolated.sh`.