From a28b3b696db9ce9959d4cae8d71415399cd321cb Mon Sep 17 00:00:00 2001 From: archipelago Date: Fri, 7 Aug 2026 20:53:15 -0400 Subject: [PATCH] docs(registry-manifest-design): stop describing the pre-Phase-1 state as "today" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The header says Phases 1-3 shipped, then §1 "Where we are today" described the world before any of them: catalog carrying "version + image override only", the manifest "never registry-distributed", counts of 48 disk manifests and 28 catalog entries. A reader hits the contradiction immediately and can't tell which half is current. Retitled §1 as the pre-Phase-1 baseline it is, and added the actual state: `releases/app-catalog.json` has 66 entries and 56 embed a full `manifest` block — one for every `apps/*/manifest.yml` in the tree (the stale counts were 48 and 28). What's genuinely left is Phase 4 (build-context apps) and Phase 5 (drop `apps/` from the OTA rsync), which the phase list already marks ⏳. Also: - The install arrow claimed "render Quadlet unit"; same overstatement corrected in architecture.md and app-manifest-spec.md — Quadlet is opt-in, the default is podman create+start. - §8's open question "generated_files with inline content — already supported?" is answered: `app.files[]` takes inline `content` with placeholder rendering. Marked answered rather than leaving a resolved question looking open. Verified present and unchanged: `catalog_manifest_to_overlay`, `install_stack_via_orchestrator`, `install_immich_stack`, and the catalog-wins merge semantics. Co-Authored-By: Claude Opus 5 (1M context) --- docs/registry-manifest-design.md | 33 +++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/docs/registry-manifest-design.md b/docs/registry-manifest-design.md index 88ea41d1..f501f3c3 100644 --- a/docs/registry-manifest-design.md +++ b/docs/registry-manifest-design.md @@ -13,14 +13,26 @@ its "discovery/authenticity" layer). --- -## 1. Where we are today +## 1. Where we started (the pre-Phase-1 baseline) -Two distinct mechanisms, only one of which is registry-distributed: +This section is the problem statement the design was written against, kept for +context. **It no longer describes the running system** — Phases 1–3 shipped, so +see "Where we are now" below. -| Thing | Source | Reaches node via | Carries | +Two distinct mechanisms, only one of which was registry-distributed: + +| Thing | Source | Reaches node via | Carried | |-------|--------|------------------|---------| -| `apps/*/manifest.yml` (48) | repo working tree | **OTA**: `self-update.sh` rsyncs `apps/ → /opt/archipelago/apps/` | full manifest (the orchestrator's real source of truth) | -| `app-catalog.json` (28) | `releases/app-catalog.json` | **registry HTTP fetch**, hourly, **signed** (`app_catalog::refresh_catalog`) | version + image override only | +| `apps/*/manifest.yml` | repo working tree | **OTA**: `self-update.sh` rsyncs `apps/ → /opt/archipelago/apps/` | full manifest (the orchestrator's real source of truth) | +| `app-catalog.json` | `releases/app-catalog.json` | **registry HTTP fetch**, hourly, **signed** (`app_catalog::refresh_catalog`) | version + image override only | + +### Where we are now + +`releases/app-catalog.json` carries 66 entries, and 56 of them embed a full +`manifest` block — one for every `apps/*/manifest.yml` in the tree. So the +"catalog carries an image override only" gap below is closed for image-only +apps; what remains is build-context apps (Phase 4) and dropping `apps/` from the +OTA rsync (Phase 5). - Orchestrator registry = in-memory `state.manifests: HashMap`, populated by `ProdContainerOrchestrator::load_manifests()` walking the disk dir. @@ -44,7 +56,8 @@ binary OTA, no disk manifest. publisher: apps/*/manifest.yml ──generate──▶ releases/app-catalog.json (embeds + signs) node: refresh_catalog() ──fetch+verify──▶ /app-catalog.json load_manifests() ──merge──▶ state.manifests (catalog wins; disk = fallback) - install(app_id) ──▶ render Quadlet unit (rootless, systemd-managed) + install(app_id) ──▶ create the rootless container (Quadlet unit when + use_quadlet_backends is on; podman create+start otherwise) ``` ## 3. Schema change (`app_catalog::AppCatalogEntry`) @@ -143,6 +156,8 @@ Add a generator (extend `create-release.sh` / a small `scripts/gen-app-catalog`) separate signed blob? Inline is simplest for Phase 1; hashing aligns with the DHT image-by-digest plan and keeps the catalog small. Lean inline now, revisit at Phase 4 when build contexts (large) need addressing anyway. -- `generated_files` with inline content (vs. source-dir) — already supported in the - manifest schema? If so, registry manifests can carry small rendered files inline, - removing another disk dependency. +- ~~`generated_files` with inline content (vs. source-dir) — already supported in + the manifest schema?~~ **Answered: yes.** `app.files[]` takes inline `content` + (with `{{HOST_IP}}` / `{{NETWORK_GATEWAY}}` / `{{secret:NAME}}` rendering), so + registry manifests already carry small rendered files inline and that disk + dependency is gone. See [`app-manifest-spec.md`](app-manifest-spec.md).