@@ -4,15 +4,18 @@ Open Notebook uses a flow-driven release process. Work moves from `ready`
44issues into pull requests, pull requests merge to ` main ` , and maintainers cut a
55version when the branch has enough validated change to ship.
66
7+ This document covers both the ** mechanics** (how to cut, build and publish) and
8+ the ** confidence process** (how we know a release is good before users get it).
9+ It was redesigned during the v1.11.0 release ([ ADR-005] ( ../docs/7-DEVELOPMENT/decisions/ADR-005-release-confidence-process.md ) ).
10+
711## Release Model
812
913- Patch releases ship backwards-compatible fixes.
1014- Minor releases ship backwards-compatible features and improvements.
1115- Major releases are planned with a milestone when they include breaking
1216 changes or migrations that need user coordination.
13- - Release candidates and community soak labels are no longer part of the
14- process. Use the ` in-dev-build ` label for changes available in development
15- images and ` released ` for shipped work.
17+ - Use the ` in-dev-build ` label for changes available in development images and
18+ ` released ` for shipped work.
1619
1720## Normal Flow
1821
@@ -21,59 +24,132 @@ version when the branch has enough validated change to ship.
21243 . Merge the pull request after review and required checks pass.
22254 . Let the development build publish the ` v1-dev ` image from ` main ` .
23265 . Cut a stable release when ` main ` has a coherent set of changes ready for
24- users.
27+ users — following the confidence process below .
2528
26- ## Cutting A Stable Release
29+ ## The Confidence Process
30+
31+ Releases keep getting bigger; ad-hoc verification does not scale. Before
32+ cutting, run this sequence:
33+
34+ ### 0. Changelog audit
35+
36+ Diff ` git log <last-tag>..main ` against the ` [Unreleased] ` section of the
37+ CHANGELOG. Every merged PR must be represented (entries reference the issue
38+ number when one exists, the PR number otherwise). The changelog is the input
39+ for both the test plan and the release notes — close the gaps first, via PR.
2740
28- 1 . Confirm ` main ` is green and review the changes since the previous release.
29- 2 . Update ` pyproject.toml ` with the target semantic version.
30- 3 . Move the relevant ` CHANGELOG.md ` entries from ` Unreleased ` into a dated
31- version section.
32- 4 . Create a GitHub release for the version tag, for example ` v1.11.0 ` .
33- 5 . Run the ` Build and Release ` workflow. Push ` v1-latest ` tags for normal
34- stable releases.
35- 6 . Verify the published images are available in GHCR and Docker Hub when
36- Docker Hub credentials are configured.
37- 7 . Mark shipped issues with ` released ` and close any release-tracking tasks.
41+ ### 1. Risk-based test matrix
3842
39- ## Docker Image Publishing
43+ Build a matrix from the actual release diff: each change → what it can break
44+ and for whom → which bucket tests it. Pay special attention to
45+ ** "does the protection break legitimate use?"** for security changes (e.g. an
46+ SSRF guard vs. self-hosted Ollama on localhost) and to anything a reverse
47+ proxy, an upgrade, or a big upload would exercise.
4048
41- The publishing workflow, from local test to promoted release:
49+ Buckets:
50+
51+ - ** A — automated, high confidence, run now** : full backend suite, frontend
52+ lint/tests/production build, the smoke-e2e agent (full API happy path + UI
53+ verification), targeted regression probes for the release's specific risks,
54+ dependency audit.
55+ - ** B — automatable with investment** : decide per item whether to build the
56+ muscle now (it compounds: the image gate below started as a bucket-B item)
57+ or verify manually this once.
58+ - ** C — needs the release owner** : real provider credentials, real TTS podcast
59+ generation, visual/UX judgment, and the final check of the pushed image.
60+
61+ ### 2. The image gate — test the artifact, not the repo
62+
63+ A green suite on ` main ` is not a working image. Run:
4264
4365``` bash
44- make docker-build-local # 1. Build for the current platform, test locally
45- make docker-push # 2. Push version tags (does NOT update latest)
46- # 3. Test the pushed version in staging/production
47- make docker-push-latest # 4. Promote: push version + update v1-latest
66+ make docker-build-local # builds <version> + local tags
67+ make release-test TAG=< new> OLD_TAG=< previous>
4868```
4969
70+ This runs two scenarios against real containers (` scripts/release-test/ ` ):
71+
72+ - ** Fresh install** : empty DB → migrations on boot → in-image worker processes
73+ a source → API/frontend/nginx-proxied checks.
74+ - ** Upgrade** : boot the * published* previous image, seed data, swap to the new
75+ image on the same volume → migrations apply, data survives.
76+
77+ Caveat: ` docker-build-local ` tags with the current ` pyproject.toml ` version —
78+ ` docker pull ` the genuine previous tag before the upgrade test so you are not
79+ comparing the new build against itself.
80+
81+ ### 3. Fix loop with a re-test policy
82+
83+ Findings become focused PRs through the normal review flow. After each merge:
84+ the cheap suite always re-runs; smoke/image gates re-run only if the fix
85+ touches what they cover; manual verification is not repeated unless the fix
86+ touches what was manually verified. Pre-existing bugs found along the way that
87+ are not release regressions become backlog issues instead of scope creep.
88+
89+ ## Cutting A Stable Release
90+
91+ 1 . Confirm ` main ` is green and the confidence process above has run.
92+ 2 . Open the ** cut PR** : bump ` pyproject.toml ` , date the ` [Unreleased] ` section
93+ as ` [<version>] - <date> ` .
94+ 3 . After merge: ` make tag ` .
95+ 4 . Build and push version images ** via CI** (it holds the registry
96+ credentials): trigger the * Build and Release* workflow with
97+ ` push_latest=false ` . Local ` make docker-push ` also works but requires
98+ ` docker login ` on both registries.
99+ 5 . ** Verify the pushed image** (bucket C, final gate): run it locally with
100+ ` make release-stack TAG=<version> [DUMP=<dev-data-dump>] ` — a browsable,
101+ isolated stack, optionally with a copy of real data — and walk the core
102+ flows in the browser.
103+ 6 . Publish the GitHub release. A non-prerelease publication triggers the
104+ workflow again and pushes the ` v1-latest ` tags automatically.
105+ 7 . Verify the ` v1-latest ` manifests on Docker Hub and GHCR (both arches, both
106+ variants), and mark shipped issues with ` released ` .
107+
108+ ## Communication
109+
110+ Release notes follow this structure (see v1.11.0 as the reference):
111+
112+ 1 . One-line verdict + upgrade recommendation.
113+ 2 . Sections: Security, Features, Performance, Notable fixes.
114+ 3 . ** Behavior changes for self-hosters** — anything that can require a config
115+ tweak on upgrade gets an explicit callout.
116+ 4 . ** Thanks** — credit every contributor by handle with what they shipped
117+ (collect via ` git log <last-tag>..<tag> ` + ` gh pr view ` for handles), plus
118+ the issue reporters collectively. Never skip this section.
119+
120+ Announce on Discord after ` v1-latest ` is live.
121+
122+ ## Retro
123+
124+ Close every release by asking: what should improve in this process? Apply the
125+ accepted improvements immediately — update this document, the scripts under
126+ ` scripts/release-test/ ` , and the decision log while the context is fresh.
127+
128+ ## Docker Image Publishing (reference)
129+
50130| Command | What it does | Updates latest? |
51131| ---------| --------------| -----------------|
52132| ` make docker-build-local ` | Build for current platform only (tags ` <version> ` + ` local ` ) | No registry push |
53- | ` make docker-push ` | Push version tags to registries | ❌ No |
54- | ` make docker-push-latest ` | Push version + update ` v1-latest ` | ✅ Yes |
55- | ` make docker-release ` | Full release (same as docker-push-latest ) | ✅ Yes |
133+ | CI * Build and Release * ( ` push_latest=false ` ) | Push version tags via CI credentials | ❌ No |
134+ | GitHub release published (non-prerelease) | CI pushes version + ` v1-latest ` | ✅ Yes |
135+ | ` make docker-push ` / ` docker-push-latest ` | Local equivalents (need ` docker login ` ) | ❌ / ✅ |
56136| ` make tag ` | Create and push a git tag matching ` pyproject.toml ` | — |
57137
58- Publishing details:
59-
60138- ** Platforms:** ` linux/amd64 ` , ` linux/arm64 `
61139- ** Registries:** Docker Hub + GitHub Container Registry
62140- ** Image variants:** regular + single-container (` -single ` )
63141- ** Version source:** ` pyproject.toml `
64142- Build issues: ` docker builder prune ` , then ` make docker-buildx-reset `
65143
66- ## Manual Verification
67-
68- Before publishing a stable release, manually verify the areas touched by the
69- release. At minimum, cover:
70-
71- - installation or upgrade path changed by the release;
72- - source ingestion and processing when content or worker behavior changed;
73- - chat, search, notes, and notebooks when user workflows changed;
74- - provider setup when model, credential, or API behavior changed;
75- - Docker image startup when packaging, environment, or dependency changes
76- landed.
77-
78- Automated checks should catch regressions where possible, but the release owner
79- chooses the manual matrix from the actual changes in the release.
144+ ## Known Gotchas
145+
146+ - ** RC stack on non-default ports needs ` API_URL ` ** or the browser talks to
147+ ` host:5055 ` — on a dev machine that is the development API (data crossover).
148+ ` rc-stack.sh ` sets it; remember this for any custom setup.
149+ - ** Containerized app + host services** : credentials pointing at local
150+ services (Ollama, LM Studio) need ` http://host.docker.internal:<port> ` .
151+ - ** SurrealDB import** : ` OVERWRITE ` goes after the type keyword
152+ (` DEFINE FIELD OVERWRITE … ` ), and the exporter can leak a log line into the
153+ dump — ` rc-stack.sh ` handles both.
154+ - ** Multiple local SurrealDB instances** : check which one the dev ` .env `
155+ actually points at (` SURREAL_URL ` ) before exporting data.
0 commit comments