# Independent local deployment

These entrypoints install an empty local environment and manage its components
independently. They do not compare source revisions, image versions, release
tuples, or provenance. Image tags are accepted. The normal Controlplane and
Runtime APIs still enforce their own input contracts.

Prerequisites: Docker Compose, Python 3.10+, OpenSSL 3, the MySQL command-line
client, local Runtime/Worker/AppService/frontend images, a host-native setup
binary, and the assembled packs in this repository. On macOS the setup binary
must be a macOS executable, even though the services run in Linux containers.
Set `OPENSSL` to its executable path if `openssl` resolves to macOS LibreSSL
(for example `/opt/homebrew/opt/openssl@3/bin/openssl`).

Run commands from this repository. Choose a new, empty state directory:

```sh
python3 scripts/local_l0.py init --root "$LOCAL_STATE" \
  --runtime-image "$RUNTIME_IMAGE" --worker-image "$WORKER_IMAGE"

python3 scripts/local_app_install.py --root "$LOCAL_STATE" \
  --selection "$INSTALL_SETTINGS" --app-packs "$APP_PACKS" \
  --setup-binary "$SETUP_BINARY" --approval-publication "$APPROVAL_PUBLICATION" \
  --catalog-image "$CATALOG_IMAGE"

python3 scripts/local_l0.py activate --root "$LOCAL_STATE"

python3 scripts/local_l1.py deploy --root "$LOCAL_STATE" \
  --app-image "$APP_IMAGE" --frontend-image "$FRONTEND_IMAGE"
```

The installation settings are JSON containing `app_installation`,
`catalog_consumers`, `runtime_worker_roles`, and `frontend.publication.digest`.
The selected AppRelease package path is relative to `APP_PACKS`. An existing
resolved BOM can supply these fields; the local entrypoint does not call the
BOM validator. Pack sources and the app shell come from `stack.lock.json`.
The approval publication is the generated approval bundle consumed by Catalog.

`init` creates the database and generic L0 schema, then starts Runtime in
bootstrap mode. App installation calls the existing complete Controlplane
installation entrypoint once, then publishes application/worker configuration. `activate`
starts Runtime serving and workers. L1 deployment starts AppService and serves
the selected frontend assets. The default URL is http://127.0.0.1:3300; the
initial administrator password is written to `$LOCAL_STATE/admin-password`.

L0 and L1 use separate Compose projects on the database-owned Docker network.
Container traffic uses service DNS; published host ports remain loopback-only.
`activate` and `start` use the images selected by `init`. Image options are
accepted by `init` and `upgrade`. `start`, `stop`, `status`, and `down`
act only on the named component:

```sh
python3 scripts/local_l0.py stop --root "$LOCAL_STATE"
python3 scripts/local_l0.py start --root "$LOCAL_STATE"
python3 scripts/local_l1.py stop --root "$LOCAL_STATE"
python3 scripts/local_l1.py start --root "$LOCAL_STATE"
```

For a code-only L0 upgrade against the current installation:

```sh
python3 scripts/local_l0.py upgrade --root "$LOCAL_STATE" \
  --runtime-image "$RUNTIME_IMAGE" --worker-image "$WORKER_IMAGE"
```

Image tags remain accepted without source or provenance comparison. Worker
ownership uses the image identity and its revision label, or `local` when no
label is supplied, exactly as installation does. Runtime remains responsible
for validating those inputs against its binary; the local fallback does not
guarantee that a particular Worker binary will accept that configuration.
Worker database pools use
the same four open / two idle connection limits as the Test2 L0 topology. The command stops L0,
advances Worker ownership through the existing control-plane CAS, preserves all
other installed role fields, and starts the replacement processes. Upgrade and
start retain the mode selected in `l0/compose.json`; prepared installation files
do not activate Runtime. Only `activate` selects serving. Prepared Worker
bindings are refreshed even when Runtime remains bootstrap. It does not
install or apply packs. If this state predates persistence of the control-plane
image, supply the existing image with `--catalog-image`. A partial upgrade can
be retried with the same target; ownership conflicts fail closed. Startup waits
up to 180 seconds for all selected processes to run and declared Worker
healthchecks to pass, including runtime-owned cutover safety windows; transient unhealthy/restarting
states do not end that wait early. Runtime API readiness remains its existing
HTTP live/ready check; no inherited Docker healthcheck is required.

L1 can be deployed again with another AppService or frontend image without
reinstalling metadata. Each deployment extracts frontend assets into a fresh
directory and replaces the frontend container mount. Restarting services preserves the database. `down`
removes that component's containers; it does not remove the separate database
project or its volume. This installer targets first installation, with no
upgrade, rollback, or partial-install recovery controller.

Commands propagate subprocess failures and have bounded startup deadlines.
Redirect output to a file when running an install. `timings.jsonl` records
operation durations and outcomes in the state directory.

## Verification scope

This is the maintained local functional verification entrypoint. The previous
combined BOM-based local installer and its external-operator instructions have
been retired. Start with a fresh state directory; old installer state is not
an input to these scripts. Existing old clusters require separately scoped
cleanup; do not reinterpret their state or volumes as a new installation.

Record the selected images, installation settings, AppRelease/final pack and
API/browser/worker cases actually exercised. The installer does not apply
business Seed profiles or provide an Integration-service lifecycle; tests that
need those dependencies must supply their declared fixtures/services or use
the matching Test environment.

Use [the environment controllers](../deployments/README.md) and their runbooks
for Test/Staging production-simulation verification, including supported
upgrade/migration, production topology, restart/failure and integration cases.
Use the relevant acceptance runner and record exact deployed digests, metadata
revision, topology and results. Component-only Test operations prove only that
component's scope. Formal Staging-to-Prod promotion continues to require its
signed resolved BOM and Staging evidence; local first-install success is not a
substitute for that evidence.
