The policy accepted only `staging` as a head for main, so any change
production needed before the next promotion had nowhere to go: the PR was
unmergeable by CI and branch protection blocks direct pushes.
Accept `hotfix/*` and `release/*` heads as well. The naming requirement
keeps a direct-to-main change deliberate and visible, and the master
freeze plus the "features target staging" rule are unchanged. Document
the escape hatch and the need to land the same commit on staging.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Record three confirmed v1.0.8 failure modes (expo prebuild native
regressions, npm 10/11 lockfile divergence, local EAS build
preconditions) and promote each into docs/releasing.md, a new
docs/development/dependencies.md, and the release-preflight script.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
AAB sha256 4893ee6f64f90bb1b2e1f13c6b088cbe75103337fbc101751da7076224778c29
verified: com.sauci.app 1.0.8 (51), production upload key, four ABIs,
Worklets/Reanimated/Skia libraries, no broad media read permissions,
production OTA endpoint, channel, and code-signing certificate. Supersedes
the build 50 artifact, which predated the skia 2.6.9 bump and the
expo-av migration and was quarantined unshipped.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
IPA sha256 760517ccf474d496c940c3f84825f4852306d840d913090610a77dc24450ee36
verified: com.sauci.app and com.sauci.app.LiveDrawWidget both 1.0.8 (47),
team BXVPBATDZY, associated domains, shared app group, production OTA
runtime, endpoint, and code-signing certificate, no dev-launcher keys.
Also syncs the tracked Podfile.lock to the archive's resolution (expo-av
removed; ExpoVideo, ExpoAudio, ExpoSystemUI added; skia 2.6.9).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
AAB sha256 29c9bee3949e51b027c558637c04eefec96bf7f177151cb9571ca2a289ffee4e
verified: com.sauci.app 1.0.8 (50), production upload key, four ABIs,
Worklets/Reanimated/Skia libraries, no broad media read permissions,
production OTA endpoint, channel, and code-signing certificate.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The upload execution policy stopped an agent at upload: App Review
submission and rollout each needed their own explicit authorization, so a
request to ship a release ended with an artifact sitting in App Store
Connect and a question back to the user. That contradicted the harness
standard in documentation/standards/react-native.md, which has always
authorized the full pipeline, and it is the wrong default: every step from
here is recoverable. A submission can be cancelled while it waits for
review, a phased release paused, a staged rollout halted.
A release request now authorizes build, verification, upload, App Review
submission, and rollout for the platforms it names.
What still needs its own authorization is anything that is not part of
shipping the requested release: widening TestFlight distribution to new
groups, and re-uploading after an ambiguous upload result. The existing
automatic-TestFlight-distribution check before an iOS upload is unchanged.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Bump expo, react, react-native, and all expo-* / react-native-* peers to
the SDK 56 line via expo install --fix, adding expo-splash-screen and
expo-system-ui for config plugins the SDK split out of core. Bump
@bacons/apple-targets, react-native-view-shot, and other native modules
to versions compatible with React Native 0.85 and the new architecture.
Remove @react-navigation/* direct dependencies and route their hooks
through expo-router, which is no longer compatible with react-navigation
as of SDK 56. Fix RN 0.85's removed StyleSheet.absoluteFillObject (use
absoluteFill) and react-native-view-shot 5.x's ViewShotRef type across
call sites. Downgrade eslint-plugin-react-hooks v7's new React Compiler
era rules to warnings pending a dedicated refactor, and repair Jest
fallout from the jest-expo/reanimated/worklets/expo-media-library bumps.
Regenerate the committed ios/ and android/ native projects with
`expo prebuild --clean` (required for @bacons/apple-targets 5.x) against
the production release channel, and document that requirement.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Server registration is complete: app id 9a66f3c2-fda7-416f-87e2-6db833b32e9d,
real code-signing certificate (public half), staging/production channels
mapped server-side. Drops the app-id placeholder guard (cert guard stays) and
re-includes certificate.pem past the root *.pem ignore rule, which had been
silently excluding it.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Add docs/mobile-ota.md covering how OTA works here, the branch and channel
model, the appVersion runtime version policy and its store-build rule, the
eoas publish commands per channel, both rollback paths, the pending native
prebuild, and the exact placeholders the server deployment still has to fill.
Index it and cross-link it from the release guide.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The dare proof migration file landed on staging without a journal entry, so the
drizzle migrator would never apply it. Register it in the journal and move the
solo sealed answers migration to 0022 to keep filenames and journal order aligned.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The sender can require photo or audio proof when sending any dare,
catalogue or custom. The recipient captures and uploads the proof as a
new couple-scoped 'dare_proof' media kind and attaches it on submit;
the server enforces ownership, kind, couple, and MIME-type match.
The proof renders inline on the dare card for the sender to review
before confirming completion.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Unpaired users could only reach a waiting-room dead end and could not answer
questions until a partner joined. Responses.couple_id is now nullable so a
solo user answers immediately and banks "sealed answers" (couple_id IS NULL).
Pairing claims both members' sealed answers and computes matches for every
question both have now answered. Invite copy and the unpaired push nudge
escalate with the sealed answer count.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Expand the seeded pool from 12 to 36 questions (migration 0020) and
select 10 per session preferring questions the couple has never seen,
then least recently used, with random tiebreaks, so repeat quizzes stop
serving the same set.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Replaces the notify-me quiz stub with a full loop: quiz sessions per
couple, answer-and-guess flow, dual-direction scoring, and a score-only
share card (no question or answer content) captured via ViewShot with
Sauci branding.
API: migration 0019 (quiz_questions, quiz_sessions, quiz_answers, 12
seeded questions), new quiz domain with session start / current /
answers / result routes, couple isolation, route + integration +
scoring unit tests.
Mobile: src/features/quiz feature (intro, per-question self+guess flow,
waiting-for-partner nudge, results with breakdown), quizStore with
sign-out clearing, QuizShareModal following SharePreviewModal, discovery
QuizTile, analytics events, and tests.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Replace the assetlinks.json placeholder with the Play App Signing key
SHA-256 certificate fingerprint so Android App Links for
https://sauci.app/join/* can verify.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Adds a shareable https://sauci.app/join/{code} link as an alternative to
manually typing an 8-character invite code:
- apps/web: /join/[code] page that validates the code shape client-side,
attempts the app.sauci:// scheme link, and falls back to a large code
display with copy button plus App Store/Play Store links; PostHog events
for page view, code copy, and store-button clicks.
- apps/web: apple-app-site-association and assetlinks.json under
/.well-known so iOS Universal Links and Android App Links can verify
sauci.app for /join/*. The Android release cert SHA-256 fingerprint is a
placeholder pending the real value.
- apps/mobile: associated domains (iOS) and an intent filter (Android) for
https://sauci.app/join/*, alongside the existing app.sauci scheme.
- apps/mobile: parse incoming join links, pre-fill and highlight the code on
the pairing screen, stash the code for signed-out/mid-onboarding users and
apply it once they reach pairing, and offer a once-per-session clipboard
hand-off that is never auto-applied.
- apps/mobile: share message now leads with the join link, keeping the raw
code visible as a fallback.
- Analytics: invite_link_opened, pairing_code_prefilled (mobile);
join_page_viewed, join_page_code_copied, join_page_store_button_clicked
(web).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Keep Sol responsible for scope, steering, and final acceptance while assigning one continuous discovery, implementation, testing, and iteration unit to Terra. Route additional reviewers and runtime verification by risk and avoid redundant verification passes.
Block broad image and video read permissions in Expo config and the checked-in Android manifest. Keep picker access scoped to user-selected media and gallery saves write-only. Add regression coverage and document the release-manifest invariant.
Route Android uploads to an internal draft and bind iOS submissions to the verified App Store Connect app. Document explicit-path local artifact submission and preserve separate release authorization.
Measure untouched mobile source, add regression coverage for native media paths and account operations, and enforce ratcheting API and mobile thresholds in required CI checks.