docs: codify the release confidence process with executable tooling - #1052
Conversation
Captures the process designed and executed for v1.11.0 so every future release reproduces it: - .github/RELEASE_PROCESS.md v2: changelog audit, risk-based test matrix (buckets A/B/C), the Docker image gate, fix-loop re-test policy, CI-based publishing path, communication structure with a mandatory credits section, retro, and the gotchas that cost iterations this cycle - ADR-005: why releases now pass a risk-based confidence process gated on the real image, with the v1.11.0 evidence (bugs the unit suite could not catch: SEARCH-index ORDER BY 500, credential clear no-op) - scripts/release-test/: the harness built during v1.11.0 — fresh-install + upgrade gate (release-image-test.sh) and the browsable RC stack with optional dev-data copy (rc-stack.sh), plus compose/nginx encoding the API_URL, host.docker.internal and SurrealDB import learnings - make release-test / release-stack / release-stack-down targets
There was a problem hiding this comment.
7 issues found across 8 files
Confidence score: 2/5
- The highest risk is false-green release validation across
scripts/release-test/docker-compose.release-test.yml,scripts/release-test/rc-stack.sh, andscripts/release-test/release-image-test.sh: UI checks can hit the wrong API port, unready stacks can still report success, and invalid modes can exit cleanly, so broken images may be approved. Wire each phase to an explicitRC_API_URL, fail hard after readiness retries, and add rejecting default branches before merging. - In
scripts/release-test/docker-compose.release-test.yml, using floatingv2for SurrealDB makes release outcomes non-reproducible, so the same commit can pass or fail depending on when CI runs. Pin the DB image version (ideally digest) to stabilize the gate before merging. scripts/release-test/nginx.conflacksclient_max_body_size, so uploads over 1MB return 413 and the documented “big upload” verification can fail for proxy reasons rather than image quality. Set an explicit upload limit aligned with the test scenario before merging.Makefileforwarding ofDUMPand action handling inscripts/release-test/rc-stack.shcan silently no-op or mis-handle paths with spaces/globs, causing confusing import behavior and missed stack operations. QuoteDUMPand make unknown actions exit nonzero to reduce operator error before merge.
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="scripts/release-test/docker-compose.release-test.yml">
<violation number="1" location="scripts/release-test/docker-compose.release-test.yml:3">
P2: Release-gate results can change without a repository change because `v2` floats to later database releases. Pin the tested SurrealDB version, preferably to an image digest, so a release run is reproducible.</violation>
<violation number="2" location="scripts/release-test/docker-compose.release-test.yml:18">
P1: Browser UI checks against this release stack resolve their API to port 5055, not the stack's API port (15055/25055); they can hit a local dev API or fail. Pass each phase's API URL as `RC_API_URL` (or make it required) and assert the returned `/config` value.</violation>
</file>
<file name="scripts/release-test/nginx.conf">
<violation number="1" location="scripts/release-test/nginx.conf:5">
P2: Uploads >1MB through the nginx proxy will silently return a 413 error because `client_max_body_size` is not set (defaults to 1MB). The release process specifically calls out "big upload" as a scenario to verify, so this default could block that part of testing. Consider adding `client_max_body_size` with a reasonable limit (e.g. 100M) to avoid confusing failures during release validation.</violation>
</file>
<file name="Makefile">
<violation number="1" location="Makefile:61">
P3: Dump paths containing spaces or shell glob characters are split before `rc-stack.sh` receives them, causing import to fail or select an unintended file. Quote `DUMP` when forwarding it.</violation>
</file>
<file name="scripts/release-test/rc-stack.sh">
<violation number="1" location="scripts/release-test/rc-stack.sh:36">
P3: A misspelled action such as `rc-stack.sh uup <tag>` silently succeeds without creating or removing a stack. Add a default case that prints usage and exits nonzero.</violation>
<violation number="2" location="scripts/release-test/rc-stack.sh:61">
P2: An app that never becomes ready is reported as a usable RC stack and this command exits successfully. Fail after the final retry so release verification cannot proceed against a broken image.</violation>
</file>
<file name="scripts/release-test/release-image-test.sh">
<violation number="1" location="scripts/release-test/release-image-test.sh:146">
P2: A misspelled mode reports `0 passed, 0 failed` and exits successfully, so CI can skip the image gate entirely. Add a rejecting default branch.</violation>
</file>
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
| # Without an explicit API_URL the frontend's /config points the BROWSER | ||
| # at host:5055 — on a dev machine that is the development API, not this | ||
| # stack (silent data crossover between environments!) | ||
| - API_URL=${RC_API_URL:-} |
There was a problem hiding this comment.
P1: Browser UI checks against this release stack resolve their API to port 5055, not the stack's API port (15055/25055); they can hit a local dev API or fail. Pass each phase's API URL as RC_API_URL (or make it required) and assert the returned /config value.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At scripts/release-test/docker-compose.release-test.yml, line 18:
<comment>Browser UI checks against this release stack resolve their API to port 5055, not the stack's API port (15055/25055); they can hit a local dev API or fail. Pass each phase's API URL as `RC_API_URL` (or make it required) and assert the returned `/config` value.</comment>
<file context>
@@ -0,0 +1,43 @@
+ # Without an explicit API_URL the frontend's /config points the BROWSER
+ # at host:5055 — on a dev machine that is the development API, not this
+ # stack (silent data crossover between environments!)
+ - API_URL=${RC_API_URL:-}
+ - OPEN_NOTEBOOK_ENCRYPTION_KEY=${RC_ENCRYPTION_KEY:-release-test-key}
+ - SURREAL_URL=ws://surrealdb:8000/rpc
</file context>
| @@ -0,0 +1,43 @@ | |||
| services: | |||
| surrealdb: | |||
| image: surrealdb/surrealdb:v2 | |||
There was a problem hiding this comment.
P2: Release-gate results can change without a repository change because v2 floats to later database releases. Pin the tested SurrealDB version, preferably to an image digest, so a release run is reproducible.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At scripts/release-test/docker-compose.release-test.yml, line 3:
<comment>Release-gate results can change without a repository change because `v2` floats to later database releases. Pin the tested SurrealDB version, preferably to an image digest, so a release run is reproducible.</comment>
<file context>
@@ -0,0 +1,43 @@
+services:
+ surrealdb:
+ image: surrealdb/surrealdb:v2
+ command: start --log info --user root --pass root rocksdb:/mydata/test.db
+ user: root
</file context>
| # streaming fix must work anyway because the API sends X-Accel-Buffering: no, | ||
| # which nginx honors. Host is passed through verbatim to exercise the | ||
| # frontend's Host validation with a real proxy in the path. | ||
| server { |
There was a problem hiding this comment.
P2: Uploads >1MB through the nginx proxy will silently return a 413 error because client_max_body_size is not set (defaults to 1MB). The release process specifically calls out "big upload" as a scenario to verify, so this default could block that part of testing. Consider adding client_max_body_size with a reasonable limit (e.g. 100M) to avoid confusing failures during release validation.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At scripts/release-test/nginx.conf, line 5:
<comment>Uploads >1MB through the nginx proxy will silently return a 413 error because `client_max_body_size` is not set (defaults to 1MB). The release process specifically calls out "big upload" as a scenario to verify, so this default could block that part of testing. Consider adding `client_max_body_size` with a reasonable limit (e.g. 100M) to avoid confusing failures during release validation.</comment>
<file context>
@@ -0,0 +1,18 @@
+# streaming fix must work anyway because the API sends X-Accel-Buffering: no,
+# which nginx honors. Host is passed through verbatim to exercise the
+# frontend's Host validation with a real proxy in the path.
+server {
+ listen 80;
+ server_name _;
</file context>
| fi | ||
| compose up -d | ||
| echo "Waiting for API..." | ||
| for i in $(seq 1 30); do |
There was a problem hiding this comment.
P2: An app that never becomes ready is reported as a usable RC stack and this command exits successfully. Fail after the final retry so release verification cannot proceed against a broken image.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At scripts/release-test/rc-stack.sh, line 61:
<comment>An app that never becomes ready is reported as a usable RC stack and this command exits successfully. Fail after the final retry so release verification cannot proceed against a broken image.</comment>
<file context>
@@ -0,0 +1,75 @@
+ fi
+ compose up -d
+ echo "Waiting for API..."
+ for i in $(seq 1 30); do
+ curl -sf -m 5 -o /dev/null http://localhost:15055/docs && break
+ sleep 5
</file context>
| case "${1:-all}" in | ||
| fresh) fresh_test ;; | ||
| upgrade) upgrade_test ;; | ||
| all) fresh_test; upgrade_test ;; |
There was a problem hiding this comment.
P2: A misspelled mode reports 0 passed, 0 failed and exits successfully, so CI can skip the image gate entirely. Add a rejecting default branch.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At scripts/release-test/release-image-test.sh, line 146:
<comment>A misspelled mode reports `0 passed, 0 failed` and exits successfully, so CI can skip the image gate entirely. Add a rejecting default branch.</comment>
<file context>
@@ -0,0 +1,150 @@
+case "${1:-all}" in
+ fresh) fresh_test ;;
+ upgrade) upgrade_test ;;
+ all) fresh_test; upgrade_test ;;
+esac
+
</file context>
| # Usage: make release-stack TAG=1.12.0 [DUMP=/tmp/dev-dump.surql] | ||
| release-stack: | ||
| @test -n "$(TAG)" || (echo "usage: make release-stack TAG=<tag> [DUMP=<dump.surql>]"; exit 1) | ||
| bash scripts/release-test/rc-stack.sh up "$(TAG)" $(DUMP) |
There was a problem hiding this comment.
P3: Dump paths containing spaces or shell glob characters are split before rc-stack.sh receives them, causing import to fail or select an unintended file. Quote DUMP when forwarding it.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At Makefile, line 61:
<comment>Dump paths containing spaces or shell glob characters are split before `rc-stack.sh` receives them, causing import to fail or select an unintended file. Quote `DUMP` when forwarding it.</comment>
<file context>
@@ -43,6 +44,25 @@ docker-buildx-clean:
+# Usage: make release-stack TAG=1.12.0 [DUMP=/tmp/dev-dump.surql]
+release-stack:
+ @test -n "$(TAG)" || (echo "usage: make release-stack TAG=<tag> [DUMP=<dump.surql>]"; exit 1)
+ bash scripts/release-test/rc-stack.sh up "$(TAG)" $(DUMP)
+
+release-stack-down:
</file context>
| docker compose -p onrelrc -f "$DIR/docker-compose.release-test.yml" "$@" | ||
| } | ||
|
|
||
| case "$1" in |
There was a problem hiding this comment.
P3: A misspelled action such as rc-stack.sh uup <tag> silently succeeds without creating or removing a stack. Add a default case that prints usage and exits nonzero.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At scripts/release-test/rc-stack.sh, line 36:
<comment>A misspelled action such as `rc-stack.sh uup <tag>` silently succeeds without creating or removing a stack. Add a default case that prints usage and exits nonzero.</comment>
<file context>
@@ -0,0 +1,75 @@
+ docker compose -p onrelrc -f "$DIR/docker-compose.release-test.yml" "$@"
+}
+
+case "$1" in
+ down)
+ compose down -v
</file context>
Summary
Preserves the release process designed and executed for v1.11.0 as versioned, reproducible muscle:
Docs
.github/RELEASE_PROCESS.mdv2 — adds the confidence process to the mechanics: changelog audit → risk-based test matrix (buckets A automated / B automatable-with-investment / C release-owner) → image gate (fresh install + upgrade against real containers) → fix loop with an explicit re-test policy → CI-based publishing → communication structure with a mandatory credits section → retro. Plus the gotchas that cost real iterations this cycle (API_URL crossover, host.docker.internal, SurrealDB import quirks).sort_by=title500'd (SEARCH-index interaction) and credential clearing silently no-oped (mirror frontend/API bugs) — both caught only by this process.Tooling (
scripts/release-test/+ make targets)make release-test TAG= OLD_TAG=— automated image gate: fresh install (migrations, in-image worker, nginx-proxied checks) and upgrade-with-data scenarios, with per-phase ports and container-identity assertionsmake release-stack TAG= [DUMP=]— browsable RC stack on the local machine, optionally importing a copy of dev data, for the manual pushed-image verificationmake release-stack-down— teardownTesting
bash -non both scripts; make target arg-guards verified:localand against the final1.11.0image)scripts/check_md_links.py: all relative links resolve