Pre-build checklist — before the owner starts the W5 build
Status: Active · Last reviewed: 2026-11-15 · Owner: the owner (a person with the terminal open on the build machine). Next: post-build checklist, then List 53.
One page. Do the steps in order. Each step says what you should see and what to do when you do not. Commands are in code; copy them as they are. Nothing here asks you to print or paste a password or a key.
1. The code is committed, pushed and green
git status --short— expect nothing printed (a clean tree). If files are listed, stop: the build packages committed files, and the update baseline needs the commit number. Ask the lead to commit and push.git log -1 --format=%h— write the short hash down. It is the "source commit" you give the post-build checklist.git status -sb— the first line must not sayaheadorbehind. If it does, push or pull first.yarn check— expect it to end with exit 0. This takes minutes. If it fails, send the last 30 lines to the lead; do not build.- Lead: run the web QA build with
TWOMORE_WEB_REACT_COMPILER=1and the journeys on it, and say in one line what it found. The phone build compiles every file with the React Compiler and nothing else did: jest, the web app and its journeys ran uncompiled code, and the second W5 build failed at its second render for that reason.
2. The build service's variables (by name only)
A tester build needs no sign-in variable. The build does need the app's own settings. List them by NAME (the command prints names and visibility, not secret values):
eas env:list preview(useeas env:list productionlater for a production build).- Check that these names are present:
EXPO_PUBLIC_SUPABASE_URL,EXPO_PUBLIC_SUPABASE_PUBLISHABLE_KEY(orEXPO_PUBLIC_SUPABASE_ANON_KEY),EXPO_PUBLIC_SENTRY_DSN,EXPO_PUBLIC_KAKAO_APP_KEY,EXPO_PUBLIC_NAVER_MAPS_CLIENT_ID(the one Naver name the app reads; theEXPO_PUBLIC_NAVER_API_HUB_*names are for local scripts and must NOT be in the build environment),EXPO_PUBLIC_SUPPORT_KAKAO_CHANNEL_URL,EXPO_PUBLIC_SUPPORT_PHONE, the file variableGOOGLE_SERVICES_JSON, andSENTRY_AUTH_TOKEN. - What a missing one does: without the two Supabase names the app cannot sign anyone in and shows no friendly page (the build still succeeds, so this is the one that costs a wasted build). Without
EXPO_PUBLIC_SENTRY_DSNthe app runs and reports to the database only. Without the Naver maps name the venue map picker shows no map. Without the Kakao key the Kakao share is off. Without the support names the contact rows have no target. - The developer one-tap sign-in needs TWO names the owner may set:
EXPO_PUBLIC_DEV_EMAILandEXPO_PUBLIC_DEV_PASSWORD. The owner's instruction of 2026-11-15: while the app is being examined, every preview build carries both, so the sign-in page has the one-tap "Dev" button and nobody types (decision log S6). The values then sit in the installed app and are readable by anyone who has the file, so a preview build is installed by the owner and the lead only and is not passed on. A production build carries neither:eas env:list productionmust not list either name, and the pair comes off the preview environment before a build goes to testers who are not the owner. No build profile ineas.jsonholds any variable any more (checked 2026-11-13); do not add one. - State of the build service's preview environment on 2026-11-15: it holds
EXPO_PUBLIC_KAKAO_APP_KEYandEXPO_PUBLIC_NAVER_MAPS_CLIENT_ID, and the two developer sign-in names (EXPO_PUBLIC_DEV_EMAIL,EXPO_PUBLIC_DEV_PASSWORD): removed on the owner's word for the first two builds, put back the same evening on the owner's instruction (item 4), from the local env file by~/twomore-tools/set-build-dev-signin.mjs(never printed; the pair was checked to sign in on the hosted project first). The production environment holds neither (names read 2026-11-15). The Kakao key is NATIVE:apps/mobile/app.config.jsadds the Kakao plugin only when it is set, so a build made without it has another fingerprint (ca2f0de2was measured); the fingerprint of step 4 is computed with the build service's variables (npx eas fingerprint:generate --build-profile preview --platform android --non-interactive --json). - If a name is missing, add it with
eas env:createas written in credentials. Do not paste a value into a chat or a file.
3. The native packages match the Expo table
cd apps/mobile && npx expo install --check— expect "Dependencies are up to date".- Batch 58 applied the eleven patch updates the table asked for, and the check was run again on 2026-11-14 (batch 59 integration): it exits 0 with "Dependencies are up to date". If it does not exit 0 now, a dependency moved since 2026-11-14: stop and ask the lead;
yarn build:previewruns this check first and stops on it. yarn check:expo-sdk-table— expectOK.
4. The native fingerprint changed, as it must
The fingerprint is a short code that stands for everything native in the app. The installed old build has 2f488e4d. The new source must NOT match it, because the new build carries new native parts (the clipboard package, the photo-library and location sentences, the splash, Android backups off, the notification colour).
- Computed on 2026-11-15 after the first W5 build failed (EAS build
4a0f7492, fingerprintb7622917, seedocs/release-evidence.mdS51): Androidd51e2ac2(fulld51e2ac21438e87a0199546931d764afdfc9a051, with the build service's variables:cd apps/mobile && npx eas fingerprint:generate --build-profile preview --platform android --non-interactive --json), iOS63971091(npx @expo/fingerprint fingerprint:generate --platform ios). It moved fromb7622917on purpose: the failed build lacked the Android start-screen picture file (expo-splash-screennow names a fully transparent image,apps/mobile/assets/splash-empty.png), and batch 66 is native-neutral. Run the command again before the build: it must print the Android value above, or a native file changed after this note. - No
expo install --fixis pending, so step 3 does not change this value. - The update baseline file
apps/mobile/ota-compatibility-baseline.jsonis NOT touched now. It is updated after the build, by the steps in the post-build checklist.
5. The update guard still refuses
yarn ota:preview— expect a refusal that says the native fingerprint changed since the compatible build. That refusal is the protection: nothing can be pushed to the old build. If it publishes instead, stop and tell the lead. (Preview updates are paused until the new build exists.)- If it refuses for a different reason (a dirty tree, an unpushed commit), fix that and try again; it must end on the fingerprint reason.
6. The hosted database and functions
npx supabase migration list— both columns must end at00778(batch 60's00768and00769, batch 61's00770and00771, batch 63's00772to00774, batch 64's00775and batch 66's00776to00778are pushed by the lead). If the remote column ends lower, stop and tell the lead: do not start the hosted checks until the lead has rundb push(migrations are applied by the lead).- Optional read-only help:
node scripts/qa/hosted-ready.mjsprints the newest migration in the repository.node scripts/qa/hosted-ready.mjs --hosted --runmakes one anonymous call and says what the public endpoint shows; it cannot read the migration number without a sign-in, so the line in step 1 is the real check. - Functions: fourteen were redeployed on 2026-11-13 and
send-pushagain after batch 57.portone-webhookandverify-portone-paymentare NOT deployed on hosted: the card payment path waits for console secrets, and List 53 does not test it. If any function source changed since,npx supabase functions deploy {name}(never with--no-verify-jwt). After the lead'sdb pushof00768and00769the lead also redeploysexport-user-data(it reads the new consent column) andseed-scenario(its excusal call passes the consent); the hosted checks wait for both. - The developer functions' switch: for the test window
app_config.allow_dev_rpcsmust be on, or the dev panel,yarn debug:logs,yarn qa:telemetryandyarn qa:healthfail with a "developer account only" refusal. Ask the lead to set it for the window; it goes off at launch.
7. The seed word
The test data (List 53's accounts and clubs) is written to the hosted QA bed only when you say so, because it replaces the QA world.
- If you give the word: the lead runs
node scripts/run-scenario.mjs readiness_qa(the small world, the one for the hosted bed: it reconciles its own ratings, so List 53's score-correction steps work;readiness_fullis not for the hosted bed, because its world is left unreconciled — the reconcile takes about 28 s and is cancelled at the API's 8 s — so score corrections on it cannot complete), after setting the function secrets named in credentials (SEED_ACCOUNT_PASSWORD,SEED_ALLOWED_UIDS, and while the project is called productionSEED_PROD_UNLOCK). The seed refuses without them. - If you do not: List 53 can still be walked on the world already on hosted, but items that name a
qareadyperson cannot be done, and the lead says which. - Write your choice here before the build: seed word given, yes or no.
8. Optional — signed updates (skip for the test build)
By default an installed app accepts any update published to its channel. Signing makes the app accept only updates signed with your private key. It is safe to skip for the test campaign because production updates are launch-gated; it joins the pre-launch list (release evidence, S37 F14). The steps below are from Expo's documented procedure and were NOT run here; check the Expo page "Code signing" at the time.
- Generate the pair once, on your machine, OUTSIDE the repository (for example in a folder in your home directory that is not tracked):
npx expo-updates codesigning:generate --key-output-directory ~/twomore-secrets/keys --certificate-output-directory ~/twomore-secrets/certs --certificate-validity-duration-years 10 --certificate-common-name "Dabusi"It writes a private key and a certificate. The private key is a credential: never commit it, never paste it into a chat. Back it up like a password; if it is lost, no update can ever be signed for the builds that carry the certificate (a new build is the only way out). - Write the config block into the app:
npx expo-updates codesigning:configure --certificate-input-directory ~/twomore-secrets/certs --key-input-directory ~/twomore-secrets/keysfromapps/mobile. It addscodeSigningCertificateandcodeSigningMetadata(keyid,alg: rsa-v1_5-sha256) to theupdatesblock ofapps/mobile/app.json. The certificate is public and is committed; the build embeds it. - Publish signed updates with
--private-key-pathpointing at the private key: add it to theeas updatecommand insideyarn ota:preview(a one-line change inpackage.json, the lead's). The update guard is unchanged. - What breaks if only one side has it: a build that carries the certificate REJECTS an update that is not signed or is signed with another key (the phone stays on its embedded or last good version, and says nothing to the person). Updates signed with a key, sent to a build with no certificate, are accepted unsigned. So: certificate in the build and a signed update = works; certificate in the build and an unsigned update = nothing updates; no certificate = signing has no effect.
- Because
app.jsonis a native-sensitive file, this changes the native fingerprint (step 4): do it BEFORE the build, or the next build. - Decision to record: signed or not for the test build. Default: not.
9. Final go
- [ ] Step 1 clean and green, hash written down: ______
- [ ] Step 2 names present
- [ ] Step 3
expo install --checkclean - [ ] Step 4 fingerprint is not
2f488e4d - [ ] Step 5 the guard refuses on the fingerprint
- [ ] Step 6 migration 00778 on both columns,
export-user-dataandseed-scenarioredeployed - [ ] Step 7 seed word: yes / no
- [ ] Step 8 signed updates: no (default) / yes
Then the lead starts the build (yarn build:preview, Android) and you continue with the post-build checklist.