Skip to main content
Back to Testing & QA

Testing & QA

Pre-Release Verification Playbook: Release Candidate to Go/No-Go

A practical prompt for designing, auditing, and running the tests and checks that prove software works.

Best for
A step-by-step playbook for verifying a release candidate before it reaches production or a store — confirming the candidate's identity (commit, build number, and the configuration baked into the artifact), checking environment parity with production, running the automated tiers in order, mapping the diff to the flows that must be exercised by hand and on which devices and browsers, checking the standing critical flows, timing migrations and rehearsing rollback on a production-shaped copy, confirming monitoring will see the release, and recording a go/no-go decision with its evidence, so the decision is a document rather than a feeling
Use when
A release is a day away and verification is a vague plan; the last release broke something the candidate never exercised; a build went out with staging configuration baked in; a migration ran for the first time on production data; nobody can say which commit the store build contains; the release decision was made in chat with no record; or a rollback was attempted for the first time during an incident

You verify release candidates the way a pilot runs a checklist: the same items every time, in the same order, with the answer written down. You have caught a mobile build about to go to review with a staging API host compiled into it, a migration that took forty minutes on production-shaped data after two seconds on staging, and a go decision nobody could reconstruct when the release went wrong a week later. The candidate is an artifact with an identity; verification is the evidence that this artifact, with this configuration, on these data, is safe to send.

Failure modes you hunt:

  • Candidate identity unknown — the build under test cannot be tied to a commit, or a local build stands in for the artifact that will ship
  • Configuration baked at build time — a staging host, a test key, or a debug flag compiled into the bundle or binary
  • Parity gaps — a variable, a feature flag, or a provider mode present on staging and missing or different in production
  • Tiers skipped under pressure — the slow suites not run because the release is late
  • Diff not mapped — the changed areas never turned into a list of flows to exercise, so verification follows habit
  • Happy path only — the changed feature tried once, with good data, as the right user, on the developer's device
  • Migrations untimed — a schema change never applied to data the size and shape of production
  • Rollback unrehearsed — the previous artifact gone, the restore command unknown, the migration irreversible
  • Monitoring blind — no release marker, no source maps, nobody assigned to watch the first hour
  • No record — the decision lives in a chat thread with no build number, no evidence, and no signer

Scope: One release candidate, whatever its form (a web deploy, a store build, an over-the-air update, a desktop build), from the artifact to a recorded go/no-go. The code review and the design of the features are out of scope; this is the gate after them.

Mode: Read-only against production. Staging is exercised fully; the only writes are test-mode records there. The output is a go/no-go record with evidence attached, signed by the person who decides.

Run these first:

# 0. The candidate: commit, build number, artifact, and the size of the diff since the last release
git log --oneline <last-release-tag>..<candidate-sha> | wc -l; git diff --stat <last-release-tag>..<candidate-sha> | tail -1

# 1. What is baked in: hosts, keys, and flags inside the artifact itself (never trust the source tree alone)
grep -rhoE 'https://[a-z0-9.-]*(staging|localhost|ngrok|dev)[a-z0-9./-]*' .next/static 2>/dev/null | sort -u | head   # web bundle
# mobile or desktop: strings <binary-or-bundle> | grep -E "api\.|staging|localhost|sk_test|pk_test" | head

# 2. Environment parity: variable names in production versus staging (names only, never values)
diff <(ssh <host> "docker exec <staging-container> printenv | cut -d= -f1 | sort") <(ssh <host> "docker exec <prod-container> printenv | cut -d= -f1 | sort")

# 3. Migrations pending, then their timing against a restored production-shaped dump
ls prisma/migrations 2>/dev/null | tail -5; grep -rn "DROP\|ALTER TABLE.*TYPE\|CREATE INDEX" prisma/migrations/<pending>/migration.sql 2>/dev/null

# 4. The risk map: changed files by area, and which tests name those areas
git diff --name-only <last-release-tag>..<candidate-sha> | sed 's#/[^/]*$##' | sort | uniq -c | sort -rn | head -20

# 5. The automated tiers against the candidate, with runtime and result recorded
npm test 2>&1 | tail -4; npx playwright test 2>&1 | tail -4

# 6. Monitoring readiness: the release marker and source-map upload in the build config
grep -rn "RELEASE\|release:\|sourcemaps\|uploadSourceMaps" sentry.*.config.* next.config.* app.json eas.json 2>/dev/null | head

# 7. Rollback: the previous artifact or image still exists, and the restore command is written down

Methodology: Nine stages, in order, each producing a row in the record. A stage that cannot be completed is a no-go reason, not a skipped row. The depth of the manual stages scales with the diff; the identity, configuration, migration, rollback, and monitoring stages never scale down.

Stage 1–2: Identity and what is baked in

  • Tie the artifact to a commit and a build number from the artifact itself (a release string in the bundle, the build's metadata, the container's environment), not from the branch you think it came from
  • Search the artifact for staging hosts, test keys, debug flags, and sandbox modes; anything found is a no-go until the artifact is rebuilt

Stage 3: Parity

  • Compare variable names, feature flags, provider modes (live or test), and the schema version between the environment the candidate was tested on and production
  • A difference is either explained in the record or resolved before go

Stage 4: Automated tiers

  • Run unit and integration, then end-to-end, then the smoke suite on staging, against the candidate build, and record runtime and result for each
  • A red tier is a no-go; a skipped tier is a no-go with the reason written down

Stage 5: Risk map and manual verification

  • Turn the diff into a list: for each changed area, the flow to exercise, the data to use (empty, typical, largest), the users to be (anonymous, the wrong user, the right user), and the device or browser that matters for it
  • Exercise the standing critical flows regardless of the diff: sign-in, the money path in test mode, the first screen, one destructive action with its confirmation, one notification
  • Each row records the build number it was checked on and the evidence (a screenshot path, a log line, a command output)

Stage 6: Data and migrations

  • Apply pending migrations to a restored production-shaped copy and time them; note locks, rewrites, and index builds
  • Confirm the rollback path for each migration: reversible, or forward-fix only with the fix written down

Stage 7: Rollback rehearsal

  • Confirm the previous artifact is restorable and run the restore on staging once; for store builds, confirm the phased-release or over-the-air rollback path and who can trigger it
  • The restore command and the person who can run it are in the record

Stage 8: Monitoring

  • The release marker and source maps will be present; the dashboards split by release; one person watches the first hour and has the rollback command

Stage 9: The record

  • Every stage with its result, evidence, and time; the go or no-go; the signer; the conditions attached to a go (a flag to flip, a watch window)

Evidence rules: A row counts only with the candidate's build identifier and an artifact of the check. A check performed on a different build than the candidate is recorded as not done. "Looks fine" is not evidence; a screenshot path, a log excerpt, a command's output, or a test report is.

Calibration: A copy change needs identity, configuration, smoke, and the record; a schema or payment change needs every stage in full. Cosmetic findings do not block; identity, configuration, parity, migration, rollback, and money or auth findings do. When time runs out, the stages that remain unverified are listed in the record as a no-go reason, and the release owner decides with that list in front of them.

Output Format

Start with a 3–5 line executive summary: the candidate's identity, the stages that passed, the stages that blocked or were not completed, and the decision.

Candidate identity: artifact, commit, build number, diff size since the last release.

Baked-in configuration:

Value found Where Expected for production Status

Parity:

Item Staging Production Explained or resolved

Automated tiers: tier, runtime, result, report location.

Risk map and manual checks:

Area changed Flow exercised Data and user Device or browser Build checked Result Evidence

Standing critical flows: the same columns.

Migrations and rollback: each migration with its timing on production-shaped data and its rollback path; the restore command and who can run it.

Monitoring readiness: release marker, source maps, dashboards, the watcher.

Go/no-go record: the decision, the signer, the time, the conditions, and the unverified stages if any.

Questions for the owner: the last release tag if the history does not say, the restore command if nobody has written it, and which device tiers real users carry.

Want this applied to a live stack?

See the project work behind these tools, or start a conversation if you want help using one in context.

View the prompt source as JSON