Skip to content

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 ​

  1. 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.
  2. git log -1 --format=%h — write the short hash down. It is the "source commit" you give the post-build checklist.
  3. git status -sb — the first line must not say ahead or behind. If it does, push or pull first.
  4. 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.
  5. Lead: run the web QA build with TWOMORE_WEB_REACT_COMPILER=1 and 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):

  1. eas env:list preview (use eas env:list production later for a production build).
  2. Check that these names are present: EXPO_PUBLIC_SUPABASE_URL, EXPO_PUBLIC_SUPABASE_PUBLISHABLE_KEY (or EXPO_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; the EXPO_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 variable GOOGLE_SERVICES_JSON, and SENTRY_AUTH_TOKEN.
  3. 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_DSN the 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.
  4. The developer one-tap sign-in needs TWO names the owner may set: EXPO_PUBLIC_DEV_EMAIL and EXPO_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 production must 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 in eas.json holds any variable any more (checked 2026-11-13); do not add one.
  5. State of the build service's preview environment on 2026-11-15: it holds EXPO_PUBLIC_KAKAO_APP_KEY and EXPO_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.js adds the Kakao plugin only when it is set, so a build made without it has another fingerprint (ca2f0de2 was 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).
  6. If a name is missing, add it with eas env:create as written in credentials. Do not paste a value into a chat or a file.

3. The native packages match the Expo table ​

  1. cd apps/mobile && npx expo install --check — expect "Dependencies are up to date".
  2. 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:preview runs this check first and stops on it.
  3. yarn check:expo-sdk-table — expect OK.

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).

  1. Computed on 2026-11-15 after the first W5 build failed (EAS build 4a0f7492, fingerprint b7622917, see docs/release-evidence.md S51): Android d51e2ac2 (full d51e2ac21438e87a0199546931d764afdfc9a051, with the build service's variables: cd apps/mobile && npx eas fingerprint:generate --build-profile preview --platform android --non-interactive --json), iOS 63971091 (npx @expo/fingerprint fingerprint:generate --platform ios). It moved from b7622917 on purpose: the failed build lacked the Android start-screen picture file (expo-splash-screen now 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.
  2. No expo install --fix is pending, so step 3 does not change this value.
  3. The update baseline file apps/mobile/ota-compatibility-baseline.json is NOT touched now. It is updated after the build, by the steps in the post-build checklist.

5. The update guard still refuses ​

  1. 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.)
  2. 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 ​

  1. npx supabase migration list — both columns must end at 00778 (batch 60's 00768 and 00769, batch 61's 00770 and 00771, batch 63's 00772 to 00774, batch 64's 00775 and batch 66's 00776 to 00778 are 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 run db push (migrations are applied by the lead).
  2. Optional read-only help: node scripts/qa/hosted-ready.mjs prints the newest migration in the repository. node scripts/qa/hosted-ready.mjs --hosted --run makes 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.
  3. Functions: fourteen were redeployed on 2026-11-13 and send-push again after batch 57. portone-webhook and verify-portone-payment are 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's db push of 00768 and 00769 the lead also redeploys export-user-data (it reads the new consent column) and seed-scenario (its excusal call passes the consent); the hosted checks wait for both.
  4. The developer functions' switch: for the test window app_config.allow_dev_rpcs must be on, or the dev panel, yarn debug:logs, yarn qa:telemetry and yarn qa:health fail 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_full is 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 production SEED_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 qaready person 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.

  1. 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).
  2. Write the config block into the app: npx expo-updates codesigning:configure --certificate-input-directory ~/twomore-secrets/certs --key-input-directory ~/twomore-secrets/keys from apps/mobile. It adds codeSigningCertificate and codeSigningMetadata (keyid, alg: rsa-v1_5-sha256) to the updates block of apps/mobile/app.json. The certificate is public and is committed; the build embeds it.
  3. Publish signed updates with --private-key-path pointing at the private key: add it to the eas update command inside yarn ota:preview (a one-line change in package.json, the lead's). The update guard is unchanged.
  4. 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.
  5. Because app.json is a native-sensitive file, this changes the native fingerprint (step 4): do it BEFORE the build, or the next build.
  6. 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 --check clean
  • [ ] Step 4 fingerprint is not 2f488e4d
  • [ ] Step 5 the guard refuses on the fingerprint
  • [ ] Step 6 migration 00778 on both columns, export-user-data and seed-scenario redeployed
  • [ ] 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.

Markdown remains the source of truth. Run yarn docs:check before handoff.