Appearance
Read before changing
- This page · 2. Process (G0–G5 and the pre-promotion checklist) · 3.
supabase/docs/PROMOTION_RUNBOOK.md· 4. HLD · LLD · Production state. The machine contract is this page'scontext:frontmatter;.claude/rules/domains/release.mdis GENERATED from it — for this domain an edit is refused until these pages were opened. Gates:check:release·check:version·check:ef-drift·check:env-drift·check:env:prod; the/promote-to-prodskill runs the checklist. Your plan must answer: which change records the change touches; which of the 17 change classes it falls in and whether a script can see that class; what the live probe is for the ones no script sees. Related domains: tools-and-gates · load-bearing-files · edge-functions. Machine reads (the manifest'sreads, in order):documentation/portal/releases/index.md·documentation/portal/releases/process.md·supabase/docs/PROMOTION_RUNBOOK.md.
Releases
The single source of truth for release management. Every production change — schema, migrations, policies, functions, config, storage, scheduled jobs, secrets, app builds, store submissions — is planned, documented, reviewed, approved and tracked here before it is deployed.
| Page | What it is for |
|---|---|
| HLD | Architecture, governance, roles, gates, integrations |
| LLD | Data model, state machine, automation, audit, notifications |
| Process | How to actually run a release, day to day |
| Production state | What is live on each surface right now |
Release register
| Version | Type | Status | Target | Frozen | Deployed | Closed |
|---|---|---|---|---|---|---|
| 26.0.1 | train_biweekly | 🔵 scoped (G0 passed 2026-08-03) | 2026-08-15 | 2026-08-12 | — | — |
Status legend: 🔵 pre-approval · 🟡 in flight / partially deployed · 🟢 closed · 🔴 rolled back
This row is pulled from release.json, not typed by hand — if it ever disagrees with that file, the file is right and this row is stale. That is precisely the failure this page had until 2026-08-03: it still said train_monthly / 🔵 draft / frozen 2026-08-11 after release.json had already moved to train_biweekly / scoped / 2026-08-12.
Roadmap
Only 26.0.1 has passed G0. Everything past it is sequencing intent, not committed scope.
Each later release gets its own G0 pass, its own scope[] referencing existing tracker ids, and its own folder — created when that release actually starts, per Starting a release below. This table exists so the cross-release sequence lives in the repo instead of only in an external planning document, which is the gap that prompted this section to be written at all. Dates beyond 26.0.1 are targets, not commitments, and will move if 26.0.1's pace does.
| Release | Target | Status | Focus | Depends on |
|---|---|---|---|---|
| 26.0.1 | 2026-08-15 (payments dark) → 2026-08-20 activation | 🔵 scoped | The complete vendor money loop: Setu Card, catalog, Razorpay Route payments. Deploys once, activates payments via kill switch — no second deploy | — |
| 26.0.2 | ~2026-09-03 | not started | Stub retirements if they slipped (QRS-323–326) · Direct Seller + Real Estate verticals · per-merchant OG image · QR display | 26.0.1 catalog + card |
| 26.1.0 | ~2026-09-17 | not started | Payments operations — vendor payments dashboard, automated payout onboarding, refunds + disputes in code (manual-with-a-runbook in 26.0.1) | 26.0.1 money model + webhook kit |
| 26.2.0 | ~2026-10-01 | not started | Admin panel + RBAC (ADR-0006, 0% built today) · feature flags (QRS-296) | 26.1.0 operational visibility |
| 26.3.0 | ~2026-10-15 | not started | Desktop DOM merchant layout (ADR-0011 amendment) + org seats | 26.2.0 admin, so seats have somewhere to be managed |
| 26.4.0 | ~2026-10-29 | not started | Leads + merged timeline + contacts · the remaining 6 launch verticals | 26.0.1 discovery-doc pattern |
| 26.5.0 | ~2026-11-12 | not started | Chat + reorder-cycle tracking (the direct-seller differentiator — MLM compensation resets monthly) | 26.4.0 leads primitive |
Why this order, not schedule padding:
- Payments operations (26.1.0) follows the money loop, not the other way round. Automating KYC and moving refunds into code both need a live, observed payments path to automate against — building the operations layer first would mean automating a process that doesn't exist yet.
- Admin + RBAC (26.2.0) is sequenced before desktop (26.3.0) on purpose. A payments product with no operational visibility is a support catastrophe, and org seats need an admin surface to manage them from — building the desktop layout first would have nothing to manage.
- Desktop is deliberately not in 26.0.1. R1 merchants (festival stalls, boutiques, electricians) are phone-first; a DOM merchant UI bought nothing in August and would have cost a fortnight against a schedule with zero slack.
- Leads/Chat (26.4.0/26.5.0) reuse the discovery-doc and reminders infrastructure built for the first three releases rather than inventing new primitives — see ADR-0009's proportionality rule (full discovery for the first domain in an archetype, a delta doc for siblings).
Metrics
Derived from the release records themselves, so there is nothing separate to keep up to date. Populated at G5; a release in flight contributes nothing yet.
| Metric | Value | Notes |
|---|---|---|
| Deployment frequency | — | releases reaching deployed per month |
| Lead time | — | G0 → deployed |
| Change failure rate | — | rolled_back ÷ deployed |
| MTTR | — | rollback trigger → resolved |
| Scope stability | — | items at G1 ÷ items at G0 |
| Gate waiver rate | — | waived gates ÷ total gates |
| Store approval latency | — | submitted → live, per platform |
| Resubmissions | — | per release, per platform |
| Open surface divergences | 0 | and their age |
These are objective. They sit alongside the delivery log's self-reported narrative under that page's own rule: where the two disagree, the numbers win.
Rules that are not negotiable
- No production change without a Change Record.
deploy-prodrefuses to apply a migration or Edge Function that is not declared in the active release'srelease.json. release.jsonis the machine source of truth. Markdown carries narrative keyed by id, andnpm run check:releaseasserts the two agree in both directions.- Approvals bind to a commit SHA and a manifest hash. Change the manifest and the approval is void.
- A release is not atomic. Per-surface
targets[];deployedis derived, never asserted. - All three surfaces ship in sync — Android native, iOS native, Web PWA. There is no exception path.
- Irreversible changes carry a forward fix, not a fictional rollback plan.
Starting a release
bash
cp -r documentation/portal/releases/_template documentation/portal/releases/<version>
# fill release.json: version, type, cadence, base_ref
npm run check:release_template/ is the canonical skeleton — copy it, never improvise a folder. The leading underscore marks it as a non-content directory (same convention as backend/edge-functions/_template.md), and the gate skips it.
Release management — the operating-manual statement
Provenance — moved from CLAUDE.md on 2026-09-23 (QRS-1288)
This is the verbatim text of CLAUDE.md § "Release management" as of commit 00c1eca, relocated here under the context-architecture programme. Sentences of the form "this said X until [date]" are corrections recorded at the time they were made; the live rule is the corrected one. Retired vocabulary inside those corrections names what was retired and is not a live claim.
Release management [ENFORCED — non-negotiable, QRS-288]
documentation/portal/releases/ is the single source of truth for every production change. Nothing reaches Prod that is not planned, documented, reviewed, approved and tracked there first. Full design: portal HLD · LLD · Process.
The one idea the whole system rests on: release documentation is LOAD-BEARING. deploy-prod.yml reads release.json and refuses to deploy a production change that is not declared in it. Docs stop being a chore done afterwards and become the thing without which the deploy does not run. That inversion exists because this repo has a measured ~0 completion rate on deferred reconciliation (QRS-180), a lint gate that once passed as a green no-op (QRS-013), and a SonarQube standard documented for months and never implemented (QRS-246). A process step that isn't gated does not exist.
release.jsonis the machine SSOT. Markdown carries narrative keyed by id;check:releaseasserts the two agree in both directions. Never record the same fact twice — that is the bug class behind QRS-249/284/287.- Scope items are existing
QRS-###ids. Releases never mint their own; the gate verifies each exists intracker.md. - Six gates, G0-G5, each with entry criteria and an exit artifact. G4 approval binds to a commit SHA + a manifest hash — edit the manifest afterwards and the approval is void. There is one maintainer and no required-reviewers on a private Free repo, so this is a guarded self-dispatch, never peer review; do not describe it otherwise in any release note or audit answer.
- A release is NOT atomic. Backend and web are push; the stores are submit-and-wait and can reject. Status is derived from per-surface
targets[], andpartially_deployedis a normal state. - A release is not a Build. Every store resubmission needs a new build number, so Android and iOS legitimately diverge (26.0.1 → android
26000100, ios26000101) with the same user-visible version. A "no functional delta" claim is proven by comparing commit SHAs, never asserted. - Contraction is bounded by the oldest live app build. Any
DROP/narrowing/EF-signature change declaresrequires_min_app_build; the gate fails if it exceeds the floor. This is the enforceable form of "multiple app versions are live, so expand-contract is structural". - Never raise a platform's
min_supported_version_codeabove its live build — it bricks every user on that platform. The gate cross-checks againstreleases/production-state.md. - Irreversible changes carry a
forward_fix, not a rollback section. A rollback plan for a burnedversionCodeor a completed data migration is fiction and produces false confidence. - Nine of the 17 change classes are invisible to every automated gate —
ef_secret,storage,cron_job,auth_setting,cloudflare,third_party, and all three app classes. Every auth incident in this project came from one of them (QRS-261/273/276/285). Their evidence must be a live functional probe, never a claim that a value was set: QRS-273 was closed on such a claim and the auth log later proved sign-in had never once worked. - Ad-hoc scope is decided by objective triggers, not judgement — see the process page. Zero triggers ⇒ accept without ceremony; a process that treats a copy fix like a schema change gets bypassed for both. After scope freeze, only P0/P1 defects in accepted scope.
- Gate runs in pre-push and in
release-gate.yml(path-filtered tosupabase/**+releases/**; deliberately NOT inci.yml, whosepaths-ignoreexcludes exactly those paths).