Pin images by digest; add update, smoke-test and status scripts
Goal: at every session start, run exactly the application the repo says — and be able to move to a new upstream release deliberately, with a way back. The old setup (v1-latest + pull_policy: always) was unreliable in both directions. `docker compose up -d` silently pulled a new application, including an irreversible SurrealDB schema migration, while a reboot (restart: always) or `docker compose start` kept running the old image without pulling anything. The running version was effectively unpredictable. Note v1-latest tracks releases, not main: the current image (v1.10.0, 2026-06-18) IS the latest release — the repo being "ahead" is unreleased code, which is explicitly not wanted here. So this is about guaranteeing and detecting, not catching up. - docker-compose.yml: both images pinned by digest, pull_policy: missing. - scripts/check_updates.sh: reports running version/digest vs the latest release and registry digest. Changes nothing; meant for the session-start ritual. - scripts/update_stack.sh: resolve new digest -> stop -> back up surreal_data, notebook_data and docker-compose.yml -> repin -> start -> smoke test -> roll back data AND compose file if the smoke test fails. The data backup is the point: the app migrates the DB on startup and an older app cannot read a migrated DB, so a bad update would otherwise be a one-way door. tar runs inside a container because the data dirs are root-owned and the host user cannot restore over them. - scripts/smoke_test.sh: checks what actually breaks here, not just "does it start". Every local adaptation leans on upstream internals and can break silently: the prompts/podcast directory mount masks the image's directory (a new template upstream would be invisible), config/content_core.yaml freezes content-core's defaults (because CCORE_CONFIG_PATH replaces rather than merges), and the env-var workarounds depend on current content-core/esperanto/podcast_creator behaviour. So it verifies those assumptions explicitly, plus API, TTS audio, STT and a real YouTube transcript. Both scripts read the digest from the lfnovo/open_notebook line specifically. A naive "first sha256 in the file" grep matches surrealdb (listed first) — caught while testing: check_updates.sh falsely reported an update, and update_stack.sh would have rewritten the database image instead of the application. Verified: smoke test green against the current stack, and red (exit 1) when failures are injected (dead TTS port, removed template variable). Backup/restore mechanics exercised separately: 44 MB in 3.3s, restore yields 13 DB files and 91 notebook files. The update path itself cannot be exercised end to end until a newer image exists. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
f350e49bd5
commit
4805fe75ed
7 changed files with 434 additions and 7 deletions
53
CLAUDE.md
53
CLAUDE.md
|
|
@ -9,13 +9,62 @@ This is a local Docker Compose deployment of [Open Notebook](https://github.com/
|
|||
## Commands
|
||||
|
||||
```bash
|
||||
docker compose up -d # start (pulls images per pull_policy: always)
|
||||
docker compose up -d # start (images are digest-pinned; no implicit upgrade)
|
||||
docker compose down # stop and remove containers (data volumes persist)
|
||||
docker compose logs -f open_notebook # follow app logs
|
||||
docker compose ps # container status
|
||||
|
||||
./scripts/check_updates.sh # is there a newer release? (reports only, changes nothing)
|
||||
./scripts/update_stack.sh # backup -> update -> smoke test -> rollback on failure
|
||||
./scripts/smoke_test.sh # verify the stack still does what we rely on
|
||||
```
|
||||
|
||||
No build/lint/test suite exists in this repo — nothing here to run.
|
||||
`smoke_test.sh` is the closest thing to a test suite here — run it after touching
|
||||
`docker-compose.yml`, the bind-mounted overlays, or the host TTS/STT services.
|
||||
|
||||
## Image versioning
|
||||
|
||||
Images are **pinned by digest**, and updating is an explicit act — never a side effect of
|
||||
starting the stack.
|
||||
|
||||
The previous setup (`v1-latest` + `pull_policy: always`) was unreliable in *both* directions:
|
||||
`docker compose up -d` silently pulled a new application — including an irreversible SurrealDB
|
||||
schema migration — while a reboot (`restart: always`) or `docker compose start` kept running the
|
||||
**old** image without any pull. So the running version was essentially unpredictable.
|
||||
|
||||
Note `v1-latest` tracks *releases*, not `main`: the tag lags the repo by weeks. Chasing `main`
|
||||
would mean building from source and running unreleased code — explicitly not wanted here.
|
||||
|
||||
Updating (`scripts/update_stack.sh`): resolve the new digest → stop → back up `surreal_data` +
|
||||
`notebook_data` + `docker-compose.yml` into `backups/<ts>/` → rewrite the digest → start → run
|
||||
`smoke_test.sh` → **roll back data and compose file if the smoke test fails**. The data backup is
|
||||
the point: the app migrates the database on startup, and an older application generally cannot
|
||||
read a migrated database, so a bad update would otherwise be a one-way door. Backup/restore runs
|
||||
`tar` **inside a container** because the data directories are root-owned (the container writes as
|
||||
root) and the host user cannot restore over them.
|
||||
|
||||
Both scripts read the digest from the `lfnovo/open_notebook` line specifically — a naive "first
|
||||
sha256 in the file" grep picks up **surrealdb** (it is listed first), which would make the update
|
||||
script rewrite the database image instead of the application.
|
||||
|
||||
### Why a smoke test, and not just "does it start"
|
||||
|
||||
Every local adaptation in this repo leans on upstream internals, and an update can break them
|
||||
*silently* — the stack comes up fine and misbehaves later:
|
||||
|
||||
- the `prompts/podcast/` **directory** mount masks the image's directory: a third template added
|
||||
upstream would simply be invisible;
|
||||
- `config/content_core.yaml` is a full dump of content-core's defaults (because `CCORE_CONFIG_PATH`
|
||||
replaces rather than merges), so new upstream defaults would be frozen out;
|
||||
- the env-var workarounds (`TTS_BATCH_SIZE`, `OPENAI_COMPATIBLE_BASE_URL_STT`,
|
||||
`ESPERANTO_TTS_TIMEOUT`) depend on how content-core / esperanto / podcast_creator behave today.
|
||||
|
||||
`smoke_test.sh` therefore checks those assumptions explicitly (template file list vs. the image,
|
||||
`{{ language }}` and `/no_think` still present, `language` still plumbed by podcast_creator,
|
||||
`TTS_BATCH_SIZE` still read, `preferred_languages` still used, esperanto still honouring
|
||||
`OPENAI_COMPATIBLE_BASE_URL_STT`, our config still covering all default keys) on top of the obvious
|
||||
end-to-end ones (API, TTS audio, STT, YouTube transcript). `SKIP_NET=1` skips the internet-dependent
|
||||
check.
|
||||
|
||||
## Architecture
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue