stress-tested against 5,000 in a week; the real plan is ~1,000 in two, with weekly releases.

Readiness audit: today's ~90 users → your actual growth plan

Four independent audits (infrastructure/DB capacity, third-party service tiers, known bugs re-assessed for scale, and crisis-safety under load) plus a direct correction pass on facts this project had gotten wrong — run against a hypothetical 5,000-in-a-week worst case as a ceiling check. Now reframed against the real number: ~1,000 users in two weeks, with a weekly iOS release cadence available. Three items were fixed outright overnight with no decision needed from you (below); the rest are yours to triage. Choose Fix before scaling · Monitor · Accept risk per finding, then copy your decisions back.

Reviewing as Marie
Read me first — the meta-finding

The single biggest thing this audit found isn't a bug. It's a pattern.

Four separate things on this list — the severity-gate fix, the classify-affect data-corruption fix, the granular-consent/analytics-gating rebuild, and the revenuecat-webhook CI fix — were reported as "fixed" earlier this week based on reading the repository, without confirming they were actually deployed or shipped. Re-checking against the live function versions and the live App Store build tonight found: the classify-affect fix was never actually deployed (live was still the vulnerable version — this one is now genuinely fixed and verified live, see below); the consent/analytics-gating rebuild is real code sitting on a branch with no upstream, so every sign-up today still gets zero consent gating; same for the severity gate and the CI fix. None of these are bugs in the fixes themselves — the code is right. The gap was verification: "committed" was treated as "live." That's now fixed as a habit, not just as four individual items — every finding below states plainly whether it's live today, fixed but not shipped, or still broken either way.

The other big correction — found mid-audit, fixed same day

Anthropic is a real data processor. It wasn't in the DPIA, the ROPA, or the privacy policy draft until tonight.

Earlier this week this project concluded recommend-plan was "100% Postgres FTS, no LLM call in the live path" — stated as verified fact, used to write the DPIA and ROPA, and repeated in the privacy-policy draft. It was wrong. The live app (v2.2, build 5, and every version since v2.1(4)) sends a version-gate header that activates a live Claude/Anthropic composition path — FTS is the fallback only, not the primary path. Separately, check-in text has always gone to Anthropic (via classify-affect/classify-crisis, unconditionally) — that part was documented correctly elsewhere in the project the whole time, just stated backwards in the ROPA. Net effect: both check-in free text and beliefs-plan intake are sent to Anthropic on essentially every user action. The DPIA, ROPA, deep-dive wiki, and the privacy-policy draft artifact have all been corrected tonight — Anthropic is now named as a processor everywhere it should be, and the privacy-policy draft's "never shared with anyone" line (which also missed this) has been rewritten. What's still missing: a signed DPA with Anthropic, and a consent step that names it specifically — the single highest-priority GDPR gap this whole project has found.

Fixed automatically tonight — nothing here for you to decide

Three items closed out while you were away

  • classify-affect's data-corruption bug — deployed and verified live. The fix (validating the model's output against the real schema instead of silently corrupting on a bad response) was written days ago but never actually shipped — confirmed by downloading the function that's genuinely running in production and finding the old, unguarded version. Deployed for real tonight, then re-downloaded and re-checked to confirm the fix is in the file that's actually live. Every check-in from this point on is protected.
  • Missing database index on `emotional_sessions` — created and verified live. The busiest table in the schema had no index on `user_id`, meaning every check-in history read did a full-table scan. Confirmed the exact live column names directly against the database first (no guessing), created the index, then re-ran the query plan and confirmed Postgres now uses it. Purely additive — nothing about the app changed, it just got faster under load.
  • The `stuck`/`stuckness` seed-file landmine — defused locally, needs your push. Retagged and committed on the backend branch. This one stops short of "fully done" only because pushing a branch is its own separate approval, same as any push — not because there's a decision left to make about the fix itself.
  • New crisis-safety bug found and fixed — the back-button race. A back-tap during an in-flight crisis classification could discard a true-positive result before it was ever checked. Fixed with the smallest possible change: the back button now waits for the classification to finish, exactly mirroring the guard the forward button already had — one line, no new state, no visual change. Committed locally on the iOS branch. Same as the consent/severity-gate fixes below: correct and ready, just needs to ride along in the next release.
  • A second instance of the same bug, one level up — found by a targeted follow-up hunt, and fixed. After the first fix, dispatched a specific search for the same pattern elsewhere. Found one more: the outer check-in screen has its own generation guard around the full crisis-routing call, and while a full-screen loading overlay blocks a normal finger-tap from reaching the back button during that window, that's visual hit-testing, not an actual guard — a VoiceOver or Switch Control user navigating by element could still activate the back button and trigger the exact same silent discard, just via a narrower, assistive-technology-specific path. Fixed the same way: gate the actual back-navigation action itself (not just the visual overlay) on the same processing flag, so it's closed for every input method, not just touch. One line, reuses existing state, no visual change, nothing different for anyone using the app normally today. Committed locally.

How the live pieces got done without needing you at the keyboard for each one: the classify-affect deploy needed the `supabase` CLI directly, which needs a one-time macOS keychain click (that's the prompt you saw) — after that, the database index was created straight through Supabase's API with a properly-decoded access token, no further prompts, no CLI, nothing else needed from you.

Answering directly — you asked "have we done the GDPR priority work? I don't know."

Where GDPR actually stands, in plain terms

Done and live in production, today: account deletion fully erases the database (verified, cascading); crisis detection (3 independent layers) is real and tested; UK Shout 85258 crisis text line is live; classify-affect's data corruption bug (fixed tonight, above).

Written and correct, sitting on a branch, NOT live yet — this is the single biggest gap between "we did the work" and "it's protecting anyone": granular consent (3 separate toggles, replacing one bundled button), analytics/Meta no longer firing before consent, the severity-gate fix, UK Shout in the in-flow crisis screen. All real, all correct, none of it reaches a single user until an app build ships. This is genuinely the top priority for your first weekly release — see the reframed timeline below.

Built and tested, not yet turned on: account-deletion erasure propagation to Amplitude + Customer.io (both live-tested with real API calls) — the function exists but hasn't been deployed to actually run when someone deletes their account.

Drafted tonight, needs your + Isabel's sign-off, not published anywhere yet: the DPIA, the ROPA, the redacted-admin-views SQL, and the corrected Privacy Policy & Terms — all real documents now (not just wiki entries describing future plans), all in ~/Documents/allin-gdpr/ or the linked drafts.

Not started, needs a decision before it can be built: the age-gate threshold (16 vs 18), the Anthropic DPA, the Amplitude Destination Filter (needs you or Isabel clicking through Segment's dashboard — 5 minutes, zero code).

Genuinely blocked on someone outside this project: Segment's own support, for the erasure API access.

Short version: the engineering is mostly done. Almost none of it has shipped. That's the real state of GDPR readiness right now — not "not done," but "done and waiting on a release + a handful of your own clicks."

Reframed with your real numbers

Not 5,000 in a week — ~1,000 in two weeks, with weekly releases available

The audit below was scoped against a hypothetical "5,000 next week" to stress-test worst-case capacity — that math still holds as a ceiling check (nothing found gets less true at a slower ramp). But the real plan you've described is gentler and, importantly, gives you a lever the original framing didn't account for: a weekly iOS release cadence. That changes several items below from "can't possibly land in time" to "this is exactly what the first or second release is for." Findings that need an actual App Store build (consent gating, the severity gate) are re-tagged below as release-cadence items, not scale emergencies — the urgency is starting the release process now, not a panic.

Bottom line

Does it survive 5,000 users?

Infrastructure: yes, gradually degrading, not falling over. Postgres is architecturally sound (everything goes through PostgREST, no raw per-request connections); the one real gap (a missing index on emotional_sessions.user_id) is cheap to fix and doesn't cause an outage, just added latency as row count compounds. Third-party services: mostly fine, one real unknown. Amplitude, Customer.io, and RevenueCat all have comfortable-to-manageable headroom or just a bill increase if crossed — Segment's actual current plan tier could not be confirmed, and if it's still Free, a second overage lockout in a 6-month window severs the entire analytics + lifecycle-email pipeline at once. Crisis safety: does not hold with full confidence. The three-layer design is real and mostly sound, but Layer B (the edge classifier) is a single attempt with no retry that fails to "false" on any error, all four AI functions share one Anthropic account's rate limits, and a genuine new bug was found — a back-button race that can discard a crisis classification result before it's checked. This is the one category where "probably fine" isn't good enough, and it's the one this audit is least confident about at 5,000 concurrent-ish users specifically because the account's actual Anthropic usage tier couldn't be confirmed from this environment.