# L1 Installer

`l1_installer.py` installs one signed L1 AppRelease into an existing neutral
L0 deployment. It deliberately has no D3 or L2 BOM input.

Inputs are the immutable AppRelease directory, its L1-owned install profile,
the deployment-approved publisher-key digest, the exact sfcrm and frontend
release digests, L0 host-compatibility facts, and the target L0 authority
epochs. The installer verifies the signed release,
rebuilds the selected pack and requires it to equal that signed release, runs
the existing pack validate/install/verify commands against the same database,
invokes an immutable published Controlplane Catalog reconcile image, and validates the resulting
AppInstallation/Catalog/Security receipt. It then renders the stopped-activation
Runtime serving document and a closed installation receipt. Workload secrets
remain L0 operator-owned inputs; the installer authorizes workload identities
but never invents or stores their credentials.

The co-located `publisher-public-key.json` is verification material only. The
required `--trusted-publisher-key-digest` must come from the deployment trust
decision and must match that key before the installer can construct a release
import. The exact validated install profile is held in memory throughout the
operation; it is not reopened after Catalog mutation.

Before any database mutation, `install` copies the release, profile, pack,
setup binary, host-compatibility documents, and database environment into one
private operation directory. Signature and byte-identity checks, setup, Catalog
reconcile, and receipt validation all consume that same snapshot. There is no
pack-install skip: a non-mutating caller uses `render`, while `install` always
runs the complete pack lifecycle before publishing serving authority.

The base sfcrm installation declares both L1 workload identities and publishes
an immutable (possibly empty) `IntegrationBindingView`. It does not grant
`runtime.commands.accept.v1` until an actual Integration binding is published.
An engine capability required by the signed AppRelease proves host
compatibility; it is not ambient serving authority.

The L0 endpoint does not restart as part of this command. Until online Catalog
activation is implemented by NexusCRM issue #4255, operators run the Catalog
step while the L0 serving deployment is stopped and then start it with the
resulting authority receipt.

The `render` subcommand is a non-mutating preflight. Run `--help` for the exact
arguments. The `install` subcommand adds the existing setup binary, database
environment, Catalog store, and exact Catalog reconcile image.
