# Deployment pipeline Build and test the runtime bundle once on the central builder. The updater and receivers verify its receipt without compiling application sources. Install the new receipt helper and receiver on every target before installing the new updater and distributor. Old receivers still compile as root. ## Flow 1. Build and test the selected revision centrally. Use `python3 deploy/capy-release-receipt.py source-digest APPLICATION` for each maintained source tree, including the staged site. Copy the exact maintained sources into the existing NativeFixture. Run the new compiler once for each distinct digest under the existing unprivileged isolation. Compare source digests before and after each check. If they differ, do not accept that digest. 2. After all checks pass, create the receipt with `python3 deploy/capy-release-receipt.py create ARTIFACT_DIR REVISION DIGEST [DIGEST ...]`. `ARTIFACT_DIR` contains `bearer_fastcgi.linux.bin`, `capyc`, `wasm/core.wasm`, and the discovered `logging/*.so` modules. The command writes `release.json` beside them. Copy this complete set into the existing `STAGING/bin` without changing its bytes. Remove old modules absent from the accepted set. The receipt contains only the revision and hashes, not sources, hosts, or credentials. 3. Check deployment approval with `deploy/capy-bearer-update --check-approval REPOSITORY REVISION`. The existing timer invokes the updater every five minutes. It fetches the candidate, scans the exact approval markers, and prepares staging sources. It verifies the staged receipt against that revision and site digest before any install. A missing or mismatched bundle stops the update. It never builds a replacement. It stops the service before replacing artifacts, restarts, checks health, and records `DEPLOYED_FILE`. 4. The updater invokes the existing distributor. It verifies the live bundle and site digest, then sends the fixed artifacts, discovered logging modules, and receipt through the existing SSH tar stream. The receiver rejects duplicate, linked, or unexpected archive members. The receiver verifies the expected revision, artifact hashes, and current `APPLICATION` digest before backup or service changes. `APPLICATION` must be configured. It stops the service before installation or rollback and preserves the existing ownership and health checks. It records the installed revision in `bin/REVISION`. The existing second argument to `capy-bearer-distribute REVISION TARGETS` still selects targets for a manual rollout. 5. `capy-package-release.timer` on the publisher (udo-aiworker) runs `deploy/capy-package-release.py` every 10 minutes. When the Gitea head equals `/deployed-revision.txt`, no package exists for it, and the revision changes a package input, the publisher asks the packaging host (capy-bearer-dev) to run `capy-package-release stage REVISION`. Place the verified bundle under the packaging host's `STATE/artifacts/REVISION/bin` before publication. The packaging host copies it into its source checkout and wraps those same binaries in both packages. It runs package layout and publication checks without rebuilding. The publisher copies the stage back, publishes to Arty with the worker token, fetches the published digest, and compares bytes. The publisher holds the token and has a working upload path to Arty. Evidence lands in `/root/capy-package-releases//` on both hosts. ## Files | File | Installed at | | --- | --- | | `deploy/capy-bearer-update` | builder `/usr/local/sbin/capy-bearer-update` | | `deploy/capy-bearer-update.default` | builder `/etc/default/capy-bearer-update` | | `deploy/capy-bearer-update.service`, `.timer` | builder `/etc/systemd/system/` | | `deploy/capy-bearer-distribute` | builder `/usr/local/sbin/capy-bearer-distribute` | | `deploy/capy-bearer-receive` | each target `/usr/local/sbin/capy-bearer-receive` | | `deploy/capy-release-receipt.py` | builder and each target, beside the deployment scripts | | `deploy/capy-bearer-receive.default` | each target `/etc/default/capy-bearer-receive` | | `deploy/capy-package-release.py` | publisher and packaging host `/usr/local/sbin/capy-package-release` | | `deploy/capy-package-release.service`, `.timer` | publisher `/etc/systemd/system/` | These files do not update themselves. Install them by hand after a change to `deploy/`. The source digest uses existing tracked `*.capy` files in a Git tree. Elsewhere, it uses recursive `*.capy` files outside `tmp` directories. Paths are relative and sorted. Each path and file body ends with a NUL byte. Accepted digests form a set. The receiver computes its source digest once before installation. Keep application sources unchanged during this operation. The existing receipt helper discovers `logging/*.so` beside the fixed artifacts. It verifies the exact module set and every artifact hash. The `paths` command exposes this set to the distributor. Install this helper with the updated receiver before the first logging rollout. No separate module helper or backend list is required. Source builds remove outputs whose backend source files no longer exist. ## Editor language servers `capyc --lsp` is part of the compiler already delivered by runtime distribution and the Debian/RPM packages. It runs under the editor user's account over stdio; do not install a system-wide LSP service or open a network port for it. The VS Code extension is a separate offline VSIX artifact built with `scripts/package_editor_tools.py`. See the [editor README](../editors/vscode/README.md) for local and Remote SSH installation and the platform-specific compiler inputs. The working-tree artifact is `dist/editor-tools/capy-language-0.3.0.vsix`. A runtime/package update does **not** install or update that extension. Install it in the extension host that opens the workspace (the remote host for Remote SSH). The extension's compiler-discovery policy and update handling are documented in [the editor README](../editors/vscode/README.md). For package-managed servers, prefer `/usr/lib/bearer/bin/capyc` over a copied compiler under a user's home directory. A source-distribution target receives `$RUNTIME/bin/capyc`; the offline editor installer separately provides `~/.local/bin/capyc`, which the extension discovers without a PATH change. The VSIX also includes only the native compiler platforms explicitly passed to its build. Neither artifact is published or installed by the runtime updater. Do not remove an existing explicit `capy.server.path` repair until the managed compiler contains the required fixes and has passed the LSP smoke tests. The working implementation, release gates, and remaining automation tasks are in [Managed editor LSP work](work/capy-managed-lsp.md). That checklist distinguishes source changes from extension releases, runtime installs, and actual editor acceptance. Package hooks must not rewrite user editor settings or kill editor processes; the extension owns its own language-server lifecycle. ## Holds and rollback - A `- [ ] DEPLOY_APPROVAL:` line in any `docs/work/*.md` file at the remote head holds the builder. Tick the box to release it. - The builder keeps the five most recent artifact sets in `/var/backups/capy-bearer//`. A target keeps five as well. Stop the service and its active socket before restoring the artifact cohort and receipt from a backup. The helper's `backup`, `install`, and `restore` commands copy the complete artifact set. Restore removes modules absent from the backup, including all modules for pre-logging backups. Backup and restore preserve file modes and ownership. If a backup has a receipt, restore verifies its hashes before copying. Older backups can have no receipt or modules. Restore its revision record, then restart the service and its previously active socket. - The package job writes `failed-` in its state directory after a failure and does not retry until that file is removed. ## Timing The runtime updater waits for a centrally checked bundle. It has no build or compiler gate time. Package timing remains separate. A revision that changes no package input gets no new package.