Context
Before the first production launch of a product, the release path needs rules that are checked, not remembered. The rules in this ADR are lessons from a previous production launch, restated in this repository’s terms. Most of them are not built yet, and the Enforcement section says which are planned. One part extends a decision already made: the service worker, which ADR 0255 did not cover. The HTML cache header of ADR 0297 stands. The owner decided these points in the final structure review of 2026-10-24.Decision
Release rules.- Secret preflight. Before a deploy starts, every secret that its runtime needs is checked to exist. A missing secret stops the deploy.
- One release unit. A frontend release waits for the backend of the same commit sha to be live. No frontend of one sha runs against a backend of another.
- Release dashboard. A dashboard shows the sha that each host serves, and it raises an alert when hosts drift apart from the release.
- Owner-approved deploy buttons. A deploy started from a button needs the owner’s approval, as a production deploy already does (0170).
- Staging on its own domain. Staging is served from its own domain, never from a production host.
- Host map, then routes, then a build-id check. The host map, which says which host serves which app, is generated from the same configuration as the routes. After a deploy, each host’s build id is checked against the release.
- Seeds. Seeds are resumable and tested. Their status is shown in the ops console. A probe checks the production
demo account (the
demoprofile of 0190). - Operator bootstrap. The first operator is created by the
stackra ops bootstrap-operatorcommand, not by a manual step. - Store checklist. The store checklist is generated from configuration (0326). Its screenshot frames are kept in the repository.
- Clean builds. A release build runs only from a clean checkout of the deployed sha. A disk-space preflight runs before the build.
- Token scopes. Each token declares its scopes, and a dry call verifies them before the token is used.
- End-to-end tests. An end-to-end test is required, or it is quarantined with a stated reason, and the quarantine list is visible.
- Worktree-safe hooks. The agent and git hooks run the same in a linked worktree as in the main checkout.
- Order. Before product features, these ship: the
PageandDataTablecomponents, the settings registry, a readiness API, a branded email kit and the ops console. This is a planning rule and has no check.
- A new worker installs and waits. It calls
skipWaitingonly when the user accepts “Reload” (rule 25). ThenclientsClaimtakes the open pages, and the page reloads once. Acriticalrelease (rule 26) skips the wait. - Navigations are network-first. The cached shell serves a navigation when the network fails.
- The worker checks the host it runs on against the host its build was made for.
- A kill-switch
sw.jscan be published to retire an installed worker. - An end-to-end test deploys one build, then a second, and checks three things. The worker of the second build waits
in
promptmode. A client of the first build still imports its lazy chunks after the second deploy (rule 29). And accepting “Reload” moves the client to the second build with one reload.
- A hashed
/assets/*path is served withpublic, max-age=31536000, immutable. sw.js,registerSW.jsand the web manifests are served withmax-age=0, must-revalidate. HTML keepsprivate, no-cachefrom 0297 decision 3: the browser revalidates it on every load, and no shared cache stores a page.- Every API response to a signed-in request, and every API response that sets a cookie, is
private, no-store. Static assets and HTML follow rules 20 and 21 whatever cookies the request carries. The gateway applies this rule (0237, amended by this ADR). It is not a per-app option. - Only a public endpoint may be cacheable: one declared
auth: falsein thepublicAPI area of 0082, with the gateway enforcing it (0237). Its cache is set by a cache profile of 0297 decision 3, and no other API response is cacheable. - Runway emits a Cloudflare Cache Rule that bypasses the cache on API hosts.
updates setting, with a mode and a critical flag.
- Web. The default mode is
prompt. The service worker downloads and installs the new version and waits (rule 15), and the page shows “New version — Reload”. - Critical web release. A release marked
criticalskips the wait of rule 15 and reloads the web app at once, without the prompt. - Mobile. Over-the-air updates (0062, EAS Update) apply on the next launch by default.
- Critical mobile release. A release marked
criticalis checked on launch, and the app reloads when it is there. - Previous build kept. After a deploy, the static host keeps the hashed assets of the previous build, at least the previous release. An open tab that lazily imports a chunk of its own build then does not 404 between the deploy and its reload.
Consequences
- The release path has one set of checks, and a launch does not depend on a person remembering them.
- The header table of rules 20 to 23 and the Cache Rule of rule 24 are gen and runway work. They are no longer a choice each app makes.
- No app can make a signed-in API response cacheable. Making an endpoint cacheable is a change to what is public, and the test of rule 22 checks it.
- Rule 14 delays product features until the foundation ships. The owner accepted that order.
- In
promptmode (rule 15) a new worker waits, so an open page keeps running its own build until the user accepts “Reload”. Its lazy chunks stay on the host (rule 29), and the deploy-twice test of rule 19 covers both.
Enforcement
- planned — no work item yet: the runway checks for rules 1, 2, 3, 6, 10 and 11 (secret preflight, one release unit, drift alerts, the host map and build-id check, the clean-checkout and disk-space preflights, and the token dry call).
- planned — the end-to-end tier of 0182 checks rule 12 (the quarantine list) and rule 19 (the deploy-twice test).
- planned — the store checklist generator has a test for rule 9.
- planned — hook tests run the guard hooks from a linked worktree (rule 13).
- planned — gen writes the header table of rules 20 to 23. A test fails when an API response to a signed-in request
becomes cacheable, and another fails when a static asset or an HTML response is marked
private, no-store(rule 22). The HTML header of rule 21 is covered by the test that 0297 already plans. - planned — a test for each update mode (rules 25 to 28).
- planned — a runway output test for the Cache Rule of rule 24, which bypasses the cache on API hosts.
- Rules 15 and 29 are covered by the deploy-twice test of rule 19 once it exists. Rules 16 to 18 have no check yet. Rules 4, 5, 8 and 14 are owner decisions or planning rules, and this page says so.