Confidential · Lucy Howell & RKWO only · Do not forward
Live Build Workspace · Updated 10 September 2026 · 3 meeting transcripts folded in

FFH Mobile App — Phase 1

Flutter shell for iOS and Android, wrapping theforce.health, piping Apple Health and Health Connect data into FFH Supabase as LIVE It Coins. Built by RKWO (London). This page is where Lucy and Rahul work the build.

Phase 1 · ~80% complete · committed $2,000 · no deposit · due on store approval TestFlight installed 8 Sept · testing now
LIVETestFlight on Lucy's phone
3P0 blockers open
15Open questions
7Compliance gates open
SOLVEDP0 identity blocker
1

Blockers

What is stopping the build from working end to end, right now.

P0 · NEW 10 Sept — RKWO sends COINS ONLY, not raw values. This breaks goal-based streaks as designed.

Said plainly by Rahul on the 7 Sept call, unprompted:

"I'm not giving you step count, by the way, just FYI… I just give you coins… There's no way you can say this person walked 10 steps based on the coins you have… It's just the calculation of coins, it's not steps."

And on the 8–9 Sept call he went further — the raw table was deliberately deleted: "originally we had a table that raw recorded the data, just to test, but then we didn't delete that table. Then came along Health Coin Awards, which does the conversion." He then ran a live migration during the call and said: "the only table you should have from our end is health_coin_awards."

The conflict, stated precisely

These two requirements cannot both hold with a fixed linear rate:

  • Compliance (Dr. Rob, 8–9 Sept): a coin total must not be reversible into a health value. "Somebody who hacks in, including a healthcare provider, there's no way they know for sure how many steps someone took."
  • Product (Lucy, throughout): the member sets a step goal, and the 3/7/14/21/30-Day Streak Challenge advances when they hit that goal.

At 15 steps = 1 coin, coins × 15 ≈ steps. Rahul conceded this: "unless they figured out the formula and worked backwards." So either the coins are reversible — and the vault claim is not true — or they are not, and the server cannot tell whether a member hit their own goal. Today the platform has neither the raw value nor a goal verdict.

The fix — and it is cheap, because the app already holds both halves:

The phone has the raw value and the formula. Let it evaluate the member's goal locally and send a verdict, not a measurement: goal_hit: true, pct_of_goal: 92, streak_day: 14 alongside the coins. A boolean is not reducible to a step count, so the vault holds — and the streak engine gets exactly what it needs. This needs the member's goal to reach the app, which the JWT session already makes possible. Raise as Q11. Owner: Rahul + Lucy.

✅ RESOLVED · 8 Sept 2026 — the identity question is answered, and it is not RKWO's problem

MIGRATION FOUND. Rahul's schema was in our own repo the whole time, one level above public/, which is why earlier passes missed it:
_shared-assets/supabase-migrations/2026-08-31-mobile-health-pipeline.sql — 9,274 bytes, committed 31 Aug (3ce79e7).

It states the answer in writing (lines 27–32), and our own coin_events RLS policy from May corroborates it independently:

-- coin_events RLS, 2026-05-22 — this only works if user_id holds the auth uuid
using (auth.uid()::text = user_id)
TableKeyed onStatus
health_samplesauth.users.id (uuid FK)✅ consistent
health_coin_awardsauth.users.id (uuid FK)✅ consistent
coin_eventsauth.users.id (as text)✅ consistent
lit_* (13 tables)profiles.id❌ the outlier

RKWO's pipeline is correctly aligned with our existing coin ledger. The mismatch is between the LIVE It Tracker tables and everything else. Because lit_* was never run in production (Gate 3 still open), it is the cheapest thing in the system to change.

→ The decision that follows: re-point lit_* at auth.users(id)

Edit 025-live-it-tracker-tables.sql before it is ever run — change all 13 FKs from profiles(id) to auth.users(id). This also fixes the P1 below for free: the lit_* RLS policies are written auth.uid() = user_id, which only ever matches if the column holds an auth uuid. Do not ask RKWO to change anything. Owner: Lucy.

P0 · SECURITY — anyone signed in can mint coins for anyone

Found 8 Sept in _shared-assets/supabase-migrations/2026-05-22-coin-events.sql. This is ours, not RKWO's — it predates the engagement.

create policy "insert_own" on public.coin_events for insert
  with check (true);   -- intentionally permissive for V1

with check (true) is no check at all. Any authenticated user can insert a coin row with any user_id and any amount. Deliberate for V1, but it has to close before coins carry real value — it undercuts the whole "coins are trustworthy" story we are selling to partners. Owner: Lucy.

P0 · SECURITY — a member can rewrite their own coin totals

In the RKWO migration, lines 140–144:

create policy "health_coin_awards_update_own"
  on public.health_coin_awards for update
  using (auth.uid() = user_id) with check (auth.uid() = user_id);

He needs an update path — the re-score-the-whole-day logic depends on it, and that logic is correct. But as written the member can set coins to any number they like. Fair question for him (Q10): can the re-score go through a security definer function so the client never writes the total directly?

P1 · Has that migration already run in production?

.github/workflows/run-migrations.yml auto-applies migrations on push to main. This one landed 31 Aug, so it has probably already been applied. Confirm rather than assume — it changes whether the RLS fix above is an edit or a live patch. Owner: Lucy.

2

Open Questions

Tick when answered. Type the answer in the box — it saves in your browser.

DOCUMENTEDRahul
Answered from his own migration — but he has NOT confirmed it verbally. Asked directly on 7 Sept, he said: "I'll have to check… I have to check the code one by one." He never came back. On 8–9 Sept he answered a different question — where it writes (health_coin_awards) — not which id. Treat as documented, not confirmed. It is the Supabase auth.users.id — declared as a uuid FK on line 47, and the file says so explicitly in its header notes. Our coin_events.user_id holds the same value as text. The gap was never on his side; it is our lit_* tables keying on profiles.id. See §1.
P1Rahul
Sample data contains duplicates — three identical steps / 2332 / COUNT rows, two active_energy / 91, two workout / 34, two steps / 609. Summed, that user "walked" 6,996 steps instead of 2,332. Rahul's whole-day re-derivation neutralises this only if the day total itself is deduped.
P1Rahul
Known bug — see §4. 14,500 steps with no workout logged pays 966 coins. The same day with a 30-minute run logged pays 300, because workout outranks steps and steps are then ignored. Logging a workout costs the member 666 coins. One-word fix: take the max within the group.
P1Rahul
The column is NOT NULL, which is a label, not a guarantee. If duplicates share a key, the constraint is missing (FFH-side one-line fix). If they carry different keys, the app is minting a fresh key per sync (RKWO-side fix).
P2Rahul
It looks like an earlier generation of health_samples — keys on profile_id not user_id, id is uuid not bigint, metric_type not metric, and recorded_at defaults to CURRENT_TIMESTAMP (wrong for backfilled health data). If both are written, FFH has two sources of truth. Drop it before real data lands, not after.
P1Rahul
The policy health_coin_awards_update_own lets a signed-in member update their own coin rows. Coins are spendable through the Force Marketplace, so that is currency minting, not leaderboard cheating. If the sync is insert-only we drop the policy. If it genuinely needs UPDATE, coin awards move server-side.
P0Lucy
Project is on Pro, which is the prerequisite — but the BAA is a separate signature in the dashboard. Until it is executed the honest answer to "is your health data under a BAA?" is no. Gate 0. No real member data until this closes. Screenshot and file it once done.
P2Lucy
Project Settings → General. This is the literal answer to "where is your health data stored," which Apple, Google, Banner, AHCCCS and every school district will ask. Should be known by heart.
P1Lucy
Rahul's model pays coins; it does not evaluate goal-hit. Streaks need a threshold — "did you clear 10,000 steps today, yes or no." lit_challenges.target_value already holds a per-challenge target and is the natural home. This layer is FFH's to build, and it is small.
P0Rahul
The health_coin_awards_update_own policy lets a member set their own coin total to any value. The re-score logic itself is right — the question is only whether the client needs direct UPDATE rights to do it, or whether a security definer RPC that recomputes from health_samples would serve the same purpose without the hole.
P0Rahul
The single most important question on this list. Without it the streak challenge cannot be driven from synced data at all — see §1. The phone holds the raw value and the formula; the platform needs only the verdict. Sending a boolean preserves Dr. Rob's non-reversibility requirement in a way that sending the raw value does not.
P1Rahul
He ran it mid-call. If health_samples is gone, then §3 of this page, the Developer Handoff, and the 31 Aug migration in our repo all describe a schema that no longer exists — and the proof-of-concept page built on raw step values is invalid. Ask for the migration file so it lands in our repo like the last one did.
P1Rahul
Promised on 4 Sept ("I'll send you that list of conversion"), again later the same call, and again on 7 Sept. Without it we cannot audit what a member is being paid for any metric except steps. Also flag: he confirmed it is based on Lucy's Meta message (150 steps = 10 points), NOT Dr. Rob's comprehensive clinical list. Rob's version was never used and he may not know that.
P0Lucy
Confirmed 8–9 Sept: "The formula lives in the app." Two consequences. Continuity: the rule that converts a member's behaviour into value sits in a Flutter codebase FFH does not hold — and no RKWO commit has ever entered our repo. Operations: changing a rate requires an app release through Apple review, not a config change. If coins are ever to carry real value, the formula belongs on the server.
P1Lucy
Raised by Lucy on 8–9 Sept. In a manual world the 50 coins pay on submittal. Connected, the sync runs every two hours by itself — so there is no "submittal" to reward. Lucy's own proposal on the call: pay at 25 / 50 / 75 / 100% of the member's goal instead. That is a product decision, and it needs writing down before the conversion table is finalised.
P0Rahul
The single highest-value ask on the list — it unlocks four things at once: server-side recomputation, the FHIR Observation code, the Provenance resource the Vault needs, and the Apple Watch demo. Both fields are already in Dr. Rob's ledger schema and wire format (§10) — this is implementing the spec, not extending it. Green tier is explicitly "full scoring, full transparency" in his own sensitivity gate. Ask for a date, not a yes.
P0Rahul
Both are Yellow tier in Dr. Rob's gate — participation only, never the value. Shipped, both use a linear rate, so coins × 5 returns sleep minutes and coins × 100 returns millilitres. We are storing sleep duration and fluid intake at full precision today. A flat rule — a fixed award for "sleep logged" regardless of duration — is the only thing that actually makes a coin non-reversible. Note this changes member earnings; pair it with Q14.
P1Rahul
iOS HKMetadataKeyWasUserEntered != true; Android RECORDING_METHOD_AUTOMATICALLY_RECORDED / ACTIVELY_RECORDED. Dr. Rob calls provenance filtering "the single most important implementation detail in the document" — any app can write steps into Apple Health. Yes or no. If no, the leaderboard is an honour system and we need to know before we promote it. Also ask before Dr. Rob's watch test, or the test proves the wrong thing.
P1Lucy + Dr. Rob
The 187-metric catalogue assigns tiers, but the ten metrics RKWO actually shipped have never been mapped against it in writing. Sleep and nutrition read as Yellow in the tier table; steps, minutes, flights, energy and stand read as Green. Get Dr. Rob to initial that list — it is what decides which metrics get real n and which get a flat rule, and it is the document counsel will ask for.
3

Data Architecture

Verified against the live database, 5–6 September 2026.

The two halves, and the seam between them

  RKWO SIDE  (keys on auth.users.id)        FFH SIDE  (keys on profiles.id)
  ─────────────────────────────────         ────────────────────────────────
  health_samples          raw stream        lit_wellness_log     steps/day
    dedupe_key, device_model                lit_challenges       target_value
    metric, value, unit                     lit_weight_entries   …
         │                                  (13 lit_* tables)
         ▼                                          ▲
  health_daily_summary    VIEW ─────╳──────────────┘
         │                        NO JOIN — the P0 blocker
         ▼
  health_coin_awards      idempotency ledger
    PK (user_id, coin_group, local_day)
         │
         ▼
  coin_events             FFH's existing balance table
    coin_type='LIVE_IT', action='health_sync'

RKWO tables — all inside FFH's Supabase

ObjectWhat it is
health_samplesRaw event stream. id bigint, user_id uuid → auth.users, metric, value float8, unit, dedupe_key text NOT NULL, device_model, created_at. Raw values, not coins.
health_daily_summaryA view — the daily rollup.
health_coin_awardsIdempotency ledger. PK (user_id, coin_group, local_day), coins = running total for that group+day after cap. This is what makes re-sync safe.
health_metricsProbable earlier generation — see Q5.

All four live in FFH's own project. No contractor holds a copy.

How coins are written

coin_events — FFH's existing balance table:

FieldValue
user_idthe uuid, as text
coin_typeLIVE_IT
amountthe delta only, never a running total
actionhealth_sync
item_idthe activity group — movement, sleep, hydration, climb, energy, mindfulness, stand
meta{group, local_day, day_total, surface:'mobile_app'}
Privacy-sound by design item_id carries the group, never the specific metric. The ledger records that coins came from moving — not that a workout happened, or how many steps. meta.day_total is a coin figure, not a measurement.

Row-level security — as it stands

TableSELECTINSERTUPDATEDELETE
health_samplesownownnonenone
health_metricsownownnonenone
health_coin_awardsownownown — see Q6none
  • Owner-scoped throughout (auth.uid() = user_id). Correct shape, and more than many low-cost builds ship with.
  • No UPDATE on the sample tables — arguably right. An append-only health record is more defensible than an editable one.
  • No DELETE anywhere. Both stores require an in-app account-deletion path and erasure requests are FFH's to answer. Confirm there is an ON DELETE CASCADE from profiles.
  • No admin and no org-scoped read. The lit_* tables carry both; these do not. So no admin dashboards through the client (a privacy win worth keeping) and no leaderboard can read these tables directly — leaderboards will need an aggregate view.
  • Verifying RLS from the dashboard as role postgres proves nothing — superuser bypasses RLS. Switch the role selector to authenticated to test properly.
4

The Coin Model

RKWO's conversion table, as supplied 6 September 2026.

The anchor

150 steps = 1 minute of effort = 10 LIVE It Coins. Everything derives from that unit: one coin costs 15 steps, one active minute pays 10. A test asserts both stay in step, so neither can be edited alone.

MetricRateCap/dayCap in real termsGroupiOSAndroid
Workouts1 min = 101,500150 minmovement ①✓✓
Exercise minutes1 min = 101,500150 minmovement ②✓—
Steps15 = 11,50022,500 stepsmovement ③✓✓
Mindful minutes1 min = 1030030 minmindfulness✓—
Active energy5 kcal = 14002,000 kcalenergy✓✓
Sleep5 min = 112010 hourssleep ①—✓
Time asleep5 min = 112010 hourssleep ②✓✓
Flights climbed1 = 210050 flightsclimb✓✓
Stand hours1 hr = 56012 hoursstand✓—
Water100 ml = 1303 litreshydration✓✓

① ② ③ = priority within the group.

Rule 1 · One metric per group pays, per day

A 30-minute run appears in Apple Health three times — as a workout, as 30 exercise minutes, and as the ~4,500 steps it produced. Paying all three would be 900 coins for half an hour. The highest-priority source with data wins; the rest are ignored.

Groups are independent, so a day of walking and good sleep and 3 litres of water earns from all three.

Rule 2 · Division floors, days re-scored on total

149 steps is 9 coins, not 9.93. Because each sync re-derives the whole day rather than a batch, the remainder isn't lost — 149 steps read ten times still pays 9, not 90.

This is the design that makes re-syncing safe, and it pairs with the health_coin_awards primary key.

Known bug — doing more can pay less

Rule 1 resolves by priority, not by value. So:

14,500 steps, no workout logged966 coins
Same day, 30-minute run logged300 coins

Workout outranks steps, so the 14,500 steps are discarded entirely. Logging the run costs the member 666 coins — the app teaches people not to record their exercise. Fix: take the highest value in the group rather than the highest priority. Tracked as Q3.

Worked examples — arithmetic verified

A day of…EarnsCheck
10,000 steps, nothing else66610000÷15 = 666.67 → 666 ✓
30-min run (+4,500 steps)300workout only, not 300+300 ✓
8 hours' sleep96480 min ÷ 5 = 96 ✓
2 litres of water202000 ÷ 100 = 20 ✓
10 flights2010 × 2 = 20 ✓
400 kcal active80400 ÷ 5 = 80 ✓
All of the above together~516300+96+20+20+80 = 516 ✓

The model is internally consistent. The only defect is the priority-vs-value resolution above.

5

Compliance Gates

No real member PHI enters the system until all five close.

Four of seven gaps found in the 5 April 2026 review were closed in code the same day — PHI localStorage guard, audit logging, consent gate, 30-minute inactivity timeout. These seven gates remain. Tick state saves in your browser.

Correction carried forward The App Deployment Tracker cites 28 January 2026 for the Google Play organization-account / D-U-N-S requirement. That date could not be substantiated. The requirement appears in Play Console Requirements with an effective date of 30 September 2026. The tracker page still shows the wrong date and should be corrected.
6

Continuity & Custody

What FFH holds if RKWO stops being available tomorrow.

Already safe

  • All data. Tables, view and ledger live in FFH's own Supabase project, on FFH's plan, under FFH's keys.
  • The pipeline keeps running. A shipped app keeps writing regardless of the developer relationship.
  • Raw values, not just coins. health_samples holds the underlying measurements, so FFH can re-derive coins under any rules it likes.
  • The schema is documented — on this page, and in project memory.

Confirm these — exposure sits here

Commercial position Phase 1 is $2,000, no deposit, payable only when both apps are live and approved. Phase 2 (RKWO builds the tracker layer) is an estimated $3,270, explicitly not fixed. Phase 1 is deliberately designed so FFH does not need Phase 2 — Rahul's own words: "the COINS data lands in a database Lucy already controls." Neither phase includes any compliance or security assurance; the proposal disclaims HIPAA explicitly. That layer is FFH's.
7

Decision & Investigation Log

What was found, when, and what it changed.

8–9 September 2026 · call 3 (Lucy, Rahul, Dr. Rob)
TestFlight finally installed · live migration run · the vault principle stress-tested
After a protracted Apple-account fight, the TestFlight build reached Lucy's phone. Rahul ran a live database migration mid-call, dropping the tables he considers surplus, on the strength of an 08:47 backup he located during the call — having first said "unless it happens automatically, I've never ran a backup." He confirmed the conversion formula lives in the app, not on the server, and agreed with Dr. Rob to remove the published "150 steps = 1 coin" line so the rate is not stated openly. Dr. Rob accepted coins-as-vault on that basis. Not resolved: that the same non-reversibility makes goal-based streaks impossible server-side (see §1). Rahul also disclaimed health_metrics — "not my table" — leaving its origin unexplained.
7 September 2026 · call 2 (Lucy, Rahul)
"I'm not giving you step count. I just give you coins."
The single most consequential sentence of the three calls, and it was said in passing. Lucy showed the steps→coins proof page; Rahul's reaction was that it is hard-coded, not pulling from the database — correct, and now doubly so, because the raw values it assumes are not being delivered. Asked directly whether coins key on profiles.id or auth.users.id, he said he would have to check the code and never came back. He also diagnosed the "8 days behind" warning: FFH and RKWO both push single files to the same repo without telling each other, so GitHub is the only source of truth and the working copy must be pulled before each session. Confirmed again: "we don't do anything for the LIVE It trackers… we hand it over to you."
4 September 2026 · call 1 (Lucy, Rahul, Dr. Rob)
App demo · ten metrics captured · replace-the-app decision taken
Rahul demonstrated the Flutter shell: a native top and bottom bar wrapping live theforce.health pages, so web changes appear instantly without an app release. Decisions taken: the new app replaces the existing Force for Health app rather than shipping alongside it (same App Store account, BuddyBoss users upgrade in place); registration deliberately opens in Safari rather than in-app, avoiding the 30–40% store commission; and gating is FFH's job, not the app's — Rahul: "I wouldn't gate it on my end. I would gate it on your end," since anyone can reach the same URL from a desktop browser. Ten metrics confirmed capturable (steps, workouts, exercise minutes, mindful minutes, activity/energy, sleep + sleep timing, flights climbed, standing hours, water), with mindful minutes and standing hours unavailable on Android. Rahul recommended FFH build a sitemap tool exposing orphan pages and stale versioned duplicates — Lucy's concern that unfinished work sits reachable in Showcase.
8 September 2026
P0 identity blocker RESOLVED — and two security holes found in its place
Connected the repo root (previously only public/ was visible) and found RKWO's migration had been in our own repo since 31 August: _shared-assets/supabase-migrations/2026-08-31-mobile-health-pipeline.sql. It answers the identity question in writing — health_samples.user_id is auth.users.id — and our own May-era coin_events RLS policy (auth.uid()::text = user_id) confirms it independently. RKWO's pipeline is correctly aligned; the lit_* tables are the outlier. Decision: re-point lit_* to auth.users(id) before it is ever run. Separately found two coin-integrity holes: coin_events insert policy is with check (true) (anyone can mint coins for anyone), and health_coin_awards lets a member rewrite their own totals. Also noted run-migrations.yml auto-applies on push, so the RKWO migration is probably already live.
7 September 2026
Steps → Coins → Earnings Log → Streak proven end to end
Built a self-contained proof page (Opportunity Items / Rahul Development / steps-to-coins-proof.html) that takes raw step values in health_samples shape, applies the member's own goal, converts at 15 steps = 1 coin with a 1,500/day cap, pays a 50-coin goal-hit bonus, writes an Earnings Log row per day and drives the 3/7/14/21/30 ladder. Five logic tests pass, including the two that matter for compliance: the daily cap holds against a 50,000-step day, and a milestone pays exactly once across a broken-and-resumed streak. Confirmed separately that no commit in the repo's 1,001-commit history is authored by RKWO — the Flutter app code has never entered our custody.
6 September 2026
Coin conversion model received; bug identified
Rahul supplied the full ten-metric conversion table, the two arithmetic rules, and the coin_events / health_coin_awards contract. Worked examples verified — all six check out. Found: group resolution by priority rather than value means logging a workout can cost a member 666 coins. Raised as Q3. Also confirmed: health_coin_awards PK (user_id, coin_group, local_day) solves idempotency, and local_day solves the timezone/day-boundary risk flagged in the handoff.
5 September 2026
P0 identity mismatch confirmed
profiles.id ≠ auth.users.id across a five-row sample. RKWO keys on auth.users; the 13 lit_* tables key on profiles. Health data and tracker data cannot currently be joined. Everything downstream blocked. Suspected cause: legacy WordPress/BuddyBoss migration ids.
5 September 2026
Schema and RLS audited against the live database
Confirmed health_samples stores raw values with units, not coins — so the concern about the coin formula being locked in the app binary is moot. Found dedupe_key NOT NULL, device_model, and the health_daily_summary view (the daily rollup previously thought missing). RLS present and owner-scoped on all three tables; gaps found: member-editable coin awards, no DELETE policies, no admin or org-scoped read. Duplicate sample rows observed across four metrics.
31 August 2026
Standing rule adopted — internal explainers ship gated + noindex
Prompted by this project's handoff document, which states openly that the BAA is unsigned and that RLS is the sole control between members' health records. Written into CLAUDE.md as a global rule with a mandatory incognito verification step. This page follows it.
25 August 2026
RKWO Phase 1 proposal received
$2,000, no deposit, payable on store approval. Phase 2 estimated $3,270. Push notifications removed from scope for speed of delivery. Filed to Opportunity Items / Rahul Development.
20 August 2026
Developer handoff built
Eleven-section engineering and compliance handoff — ten trackers, 13 lit_* tables, 59 RLS policies, seven compliance non-negotiables, the window.FFHNative bridge contract, the HealthKit / Health Connect field map, IP and security terms, twelve open decisions.
8

Artifact Index

Everything this build touches.

ArtifactWhere
Developer Handoff (gated)theforce.health/live-it-trackers-handoff/
RKWO Phase 1 ProposalOpportunity Items/Rahul Development/RKWO-TheForceForHealth_Mobile_App_Proposal.pdf
Conversion table screenshotsOpportunity Items/Rahul Development/
App Deployment Tracker (32 steps, phases 0–6)theforce.health/app-tracker/
LIVE It Trackerstheforce.health/live-it-trackers/
LIT schema migration — 13 tables, 59 policiesSupabase/025-live-it-tracker-tables.sql
Compliance & audit schemaSupabase/005-compliance-audit-tables.sql
Gamification schema — coin_transactions, badges, streaksSupabase/002-learning-gamification-tables.sql
Compliance Check & Gameplan v1.0FFH-LIVE-It-Trackers-Compliance-Check-Gameplan.docx
Leaderboard Privacy Advisory v1.0FFH-Leaderboard-Privacy-Compliance-Advisory.docx
Supabase projectkfdwkiarqxlstlsnrilj · New FFHA Network Systems · main · PRO
9

Meeting Log

Executive summaries from the three recorded calls. Source transcripts are credential-bearing — see Gate 6.

Call 3 · 8–9 September · Lucy, Rahul, Dr. Rob TestFlight delivered

In one line: the build finally reached a phone, a live migration reshaped the database mid-call, and the compliance principle was tested — and passed for the wrong reason.

Decisions taken

  • The published "150 steps = 1 coin" line will be removed so the rate is not stated openly. Dr. Rob endorsed this as the layer that makes coins non-reversible.
  • Surplus tables dropped by live migration, on the strength of an 08:47 backup found during the call.
  • Lucy proposed rewarding at 25 / 50 / 75 / 100% of goal in place of the per-submittal 50 coins, now that sync is continuous. Not yet formalised — Q15.

Confirmed

  • Sync runs automatically every two hours, plus a manual button under the profile icon.
  • De-duplication works: syncing at 1,001 steps after a 1,000-step sync yields 1,001, not 2,001. This answers Q2.
  • The conversion formula lives in the app, not the server.
  • health_metrics is not RKWO's table — origin unknown.
  • Apple Developer account is lucy@myhealthyglobe.com; lucy@theforceforhealth.com is the Sickle Cell developer identity and is not on the developer programme.

Open — Q3 (the 666-coin group-resolution bug): Rahul could not explain it on the call and committed to redo the arithmetic by hand. Dr. Rob could not interpret it either. Still open.

⚠ Security: a new Apple Developer password was set and read aloud, along with several 2FA codes. It is in the recording and in the auto-generated transcript. Rotate it — Gate 6.

Call 2 · Monday 7 September · Lucy, Rahul Architecture-changing

In one line: Rahul said in passing that he is not sending raw values at all — only coins — which invalidates the assumption the tracker integration was being designed on.

The quote that matters

"I'm not giving you step count, by the way, just FYI… I just give you coins… There's no way you can say this person walked 10 steps based on the coins you have."

Takeaways

  • The proof-of-concept page is hard-coded, not database-backed — Rahul spotted this correctly. It demonstrates the model; it does not demonstrate a live connection.
  • Why the repo was "8 days behind": both sides push single files to one repo without telling each other. GitHub is the only source of truth. Pull before every working session.
  • Local disk pressure (Lucy at ~2GB free) is self-inflicted — versions kept locally that GitHub already holds. Safe to clear, keeping the main working folder.
  • Restated: "we don't do anything for the LIVE It trackers or the tracking pages… we hand it over to you." The seam is the database and nothing else.
  • App Store copyright still read 2023; Rahul updating to 2026.

Asked and not answered: does the coin write key on profiles.id or auth.users.id? — "I'll have to check… one by one." No reply since.

Call 1 · Friday 4 September · Lucy, Rahul, Dr. Rob App demo

In one line: the Flutter shell works and is genuinely well-judged — a thin native frame around live web pages, so most future changes need no app release.

Decisions taken

  • Replace the existing Force for Health app rather than publish a second one. Same App Store account; BuddyBoss users upgrade in place. WordPress/LearnDash stays behind the scenes until fully migrated.
  • No in-app registration — "Create account" opens Safari, avoiding the 30–40% store commission on sales.
  • Gating is FFH's responsibility. Rahul: "I wouldn't gate it on my end. I would gate it on your end" — the same URLs are reachable from any desktop browser, so an app-level gate is theatre. This validates the CLAUDE.md gated + noindex standing rule as the only real control.
  • Bottom nav is fixed and requires an app release to change — Lucy to supply the final four destinations. Top bar gains Messages and Search icons.

Ten metrics confirmed capturable

Steps · workouts · exercise minutes · mindful minutes · activity & energy · sleep and sleep timing · flights climbed · standing hours · water. Android cannot supply mindful minutes or standing hours. Dr. Rob noted roughly 44 metrics exist in total; Rahul's position is to capture everything now — "you might as well have all the health data stored as coins because you might use it one day."

Notable: the conversion is built from Lucy's Meta message (150 steps = 10 points), not Dr. Rob's comprehensive clinical list. Asked directly, Rahul confirmed: "No. It was the one you sent me on Meta." Dr. Rob may not know his list went unused — worth raising with him directly.

Dates and commitments named across the three calls

WhatWhoWhen saidStatus
Conversion table for all ten metricsRahul4 Sept, twice; again 7 SeptNot delivered
List of which Supabase tables to wire upRahul4 Sept — "shortly after this call"Partly — sent via Messenger
TestFlight buildRahul4 Sept — "there will be"Delivered 8–9 Sept
Migration dropping surplus tablesRahul8–9 Sept, run live on the callDone — file not in our repo (Q12)
Re-do the 666-coin group-resolution arithmeticRahul8–9 SeptOutstanding (Q3)
Remove the published "150 steps = 1 coin" lineRahul8–9 SeptOutstanding
App Store copyright 2023 → 2026Rahul7 SeptOutstanding
Final four bottom-nav destinationsLucy4 Sept — homeworkOutstanding
App logo fileLucy4 Sept; chased 7 SeptOutstanding
Apple HealthKit entitlement + extra termsRahul → Lucy signs7 SeptPending (Gate 5)
Weekly tech talkBothMondaysRecurring
10

PHI Posture & the Reversibility Problem

Executive summary — 13 September 2026. Whether pulling the raw count breaks our arm's-length stance, and what we actually hold today.

The finding, in one line

We are not deciding whether to start holding raw health values. We already hold every one of them, at full resolution, and have since August.

A coin is only a privacy boundary if the arithmetic cannot be run backwards. Every rate RKWO shipped is linear, so every one is reversible with a calculator. The coin is a unit conversion, not a one-way door.

Coin groupRob's tierRecover the raw value byWorked example
movementGreencoins × 15612 coins → 9,180 steps
sleepYellowcoins × 596 coins → 480 minutes of sleep
hydrationYellowcoins × 10018 coins → 1,800 ml
energyGreencoins × 580 coins → 400 kcal
climbGreencoins ÷ 220 coins → 10 flights
standGreencoins ÷ 545 coins → 9 hours

96 sleep coins is not a proxy for eight hours of sleep. It is eight hours of sleep, written in a different unit. Sleep and hydration are Yellow tier in Dr. Rob's own sensitivity gate — "participation only, never the value" — and we are storing both at full precision right now.

This voids a decision taken on the 8–9 September call Correction

That call resolved to remove the published "150 steps = 1 coin" line so the rate is not stated openly, and recorded Dr. Rob endorsing this as "the layer that makes coins non-reversible." It does not make them non-reversible, for three independent reasons:

  • One data point recovers the rate. Any member can read their own step count in Apple Health and their own coin total on our page. 8,742 ÷ 582 = 15.02. The rate is not a secret we can keep from the only people who can check it.
  • Dr. Rob's own spec publishes the whole rate card — all ten metrics, rates and caps — and it has been circulated to the development team.
  • It is the exact pattern our own standing rule forbids. "Obscurity is not access control" is already written into the gated-pages rule. Hiding a rate is not the same as not having one.

The real control is a non-linear rate, not a hidden one. Dr. Rob already designed it: Yellow-tier rules pay a flat amount — 75 coins for "blood pressure logged," whatever the reading. Flat is genuinely non-invertible. RKWO shipped no flat rules at all.

What Dr. Rob's spec actually says — n was always meant to cross the wire

Adding the raw count is not a departure from the architecture. It is the architecture. His ledger schema and wire format both carry it:

player_id · local_date · rule_id · n · coins · event_id · envelope_id · created_at

"events": [
  { "rule": "bio.g.1", "n": 87, "coins": 87  },   // green — n is the real count
  { "rule": "bio.g.4", "n": 22, "coins": 220 },   // green — 22 minutes
  { "rule": "bio.y.2", "n": 1,  "coins": 75  }    // yellow — participation only
]

Green carries the count. Yellow carries only "×1, it happened." That distinction is the whole design, and it appears on the page of his spec headed "On the FFH server (the whole footprint)." RKWO dropped n; Dr. Rob specified it.

The HIPAA question, answered plainly

FFH is not a HIPAA covered entity, and a step count from a member's own watch has never been PHI. HIPAA attaches to providers, health plans, clearinghouses and their business associates. Whoop, Oura, Strava, Fitbit and WW all sit outside it and all store raw heart rate, HRV, sleep stages and GPS — far more than we are discussing. Whoop's privacy policy states it is not a covered entity in as many words.

What does reach us is a thinner, different set of rules, and this is where the caution belongs:

  • Washington My Health My Data and Nevada SB 370 — broad "consumer health data" definitions and consent duties. MHMD carries a private right of action.
  • FTC Health Breach Notification Rule — already enforced against consumer health apps (GoodRx, Premom).
  • Health Information Privacy Reform Act (Sen. Cassidy) — introduced to close the wearables gap. Track it; not law.

None of those are addressed by refusing to store n. They are addressed by consent language, retention limits, a no-sale commitment and a breach procedure. Storing less raw data is a nice-to-have there; not selling it and disclosing it clearly are the actual obligations. Counsel has still not reviewed any of this — see Gate 3.

Recommendation — implement Rob's tiering properly, and we end up holding less

TierMetricsWhat crosses the wireRate shape
Green steps, exercise minutes, workouts, flights, active energy, stand hours real n + rule_id + coinslinear is fine
Yellow sleep, hydration, and any nutrition or vitals added later n: 1 — participation onlymust be flat
Red reproductive health, clinical records, workout routes nothing — scope never requestedn/a

Net effect: we hold less sensitive data than today, and more useful data than today. Sleep and water stop being recoverable; movement becomes provable. That is a better position for a payer conversation than either the current build or a blanket refusal — and it is Dr. Rob's design, faithfully implemented rather than half-implemented.

One caveat to state out loud: moving sleep and hydration to a flat rate changes what members earn. Sleep currently pays up to 120/day and water up to 30/day on a sliding scale. A flat rule pays the same for six hours as for nine. That is a product decision, not only a compliance one — it belongs with the wider economy calibration in Q14.

11

Rahul's Build vs Dr. Rob's Document

Plain language, no jargon. What exists, what was specified, and whether we have two paths or one.

Start here — the honest status of this page

Sections 1–9 of this Build Room describe Rahul's build. They were written from his migration file, the live database and the three call transcripts. Dr. Rob's spec is not woven through them — it arrived on 21 August and only entered this page on 13 September, through §10, and only on one issue.

This section closes that gap. The full line-by-line engineering comparison lives at /biometrics-spec-gap-analysis/ — also gated. What follows is the version you can read to a board member.

The comparison, in one table

The questionWhat Rahul built What Rob's document saysDoes it matter?
Who works out the coins? The phone. The phone works it out — then the server checks it. Yes Today nobody checks. Whatever number the phone sends is the number we keep.
What the phone sends us "612 coins." "9,180 steps, which is 612 coins." Yes Without the steps we cannot check the maths, prove it to a partner, or export it to a health record.
Can we tell which activity earned a coin? No — walking, a workout and exercise minutes all arrive as one word: "movement". Yes — each coin names the rule that paid it. Yes A health system needs to know whether it was steps or a workout. They are different medical records.
Can a member change their own coin total? Yes. The database permits it. No. The server recalculates and ignores what the phone claims. Yes This is a live hole, open since August.
Can we change the coin rates without an app-store release? No — the rates are baked into the app. Yes — rates load from a spreadsheet the business controls. Medium Every pricing change waits on Rahul and on Apple's review queue.
Can we prove a coin wasn't invented? No. Yes — every batch is signed by the phone and verified by the server. Later Needed before money or prizes ride on a leaderboard.
Does a health measurement ever reach our server? No. No. Both agree This is the part that is right, and it is the hard part. Neither design sends us a heart rate, a weight or a blood pressure.

Read the last row first. The privacy architecture — the thing that took real design work and that we say out loud to partners — Rahul built correctly. What is missing is everything that makes the coins trustworthy, not everything that makes them private.

Why "two paths" is the wrong shape of question

Dr. Rob's document describes one system in two halves, and they are built by different people:

HalfWhat it doesWho can build itStatus
The phone half Reads Apple Health / Health Connect, applies the rates, sends the result. Only Rahul. It is native app code inside the app he owns. Built, and working.
The server half Receives the result, re-checks the maths, enforces the daily caps, keeps the permanent record, versions the rates, exports to health-record format. Us. Entirely. It is our Supabase. Not built. Nobody has started it.

A "parallel track" to Rob's document is not available for the phone half. Only one app on a member's phone can read Apple Health, and Rahul owns it. Building a parallel phone app does not run alongside his — it replaces his, and it needs a mobile developer we do not currently have.

But the server half needs nothing from Rahul except two extra fields. Everything else in Rob's server design — the permanent ledger, the re-check, the caps, the rate versions, the FHIR export — we can build ourselves, starting this month, without asking anyone's permission.

The three options, with honest costs

OptionWhat it costsWhat you get, and what you do not
1 Carry on exactly as now
Rahul's build, no server work
Nothing. Coins keep flowing and the app keeps working. You cannot prove a single coin, cannot export to a health record, cannot stop a member editing their own total, and cannot change a rate without an app release. Not a position to take into a payer conversation.
2 Build a parallel app to Rob's spec
a second phone app, our own
A mobile developer. Months, not weeks. Plus running two apps at once. Not actually available today We have no mobile developer. And it is not parallel — two apps cannot both own the health-data connection on one phone. This is "replace Rahul", priced honestly. Keep it on the table as a contingency, not as a plan.
3 Keep Rahul's phone. Build Rob's server ourselves.
the convergence path
Our own Supabase work. No new hire. Rahul's only obligation is to send two extra fields. Recommended Rahul's app feeds a ledger we control and verify. We get provable coins, the health-record export, rate versioning and cap enforcement — and we stop being dependent on his release schedule for anything except those two fields.

Option 3 — what we build, and what we need from him

What we need from Rahul — this is the entire list:

  • Send rule_id — which rule paid the coin.
  • Send n — the count it was worked out from.

That is Q16. Both fields are already in his own spec's ledger schema. Nothing else on this list depends on him.

What we build ourselves, in order:

#PieceEffortWhy first / why later
1Close the coin-editing holehours Do this regardless of every other decision. Drop the update permission; clamp writes in a database function. No dependency on anyone.
2Permanent append-only ledgerdays The table Rob specified. Write to it in parallel with the current one — nothing breaks while it fills.
3Stamp the rate version on every awardhours Cheap, and it stops a future rate change silently rewriting history.
4Server-side re-check + cap enforcementdays Needs Q16 first. Without n there is nothing to re-check against.
5Health-record (FHIR) exportweeks The Vault deliverable. Needs 2 and 4 in place, and the tier list signed off (Q19).

Items 1 and 3 can start today and need nobody's agreement. That is the argument for Option 3: most of the value is on our side of the line and has been the whole time.

The one decision that changes the answer

If Rahul sends rule_id and n — Option 3 is fully open and we should stop describing this as two paths. There is one system; he builds the phone half, we build the server half, and Rob's document is the shared specification both halves are measured against.

If he refuses, or goes quiet for another fortnight — that is not an engineering problem to work around. It is the signal to price a second mobile developer, because it means the phone half cannot be specified by us and we are building a company asset on top of code we cannot see, cannot verify, and cannot change. That is a board decision, and it should be taken deliberately rather than arrived at by drift.

Set the deadline when you ask. Ask for a date, and diarise it. The pattern across all three calls is that unanswered questions simply lapse — Q1 was asked on 7 September and never came back.

What Rob's document covers that neither side has built

Worth knowing so it is not mistaken for a gap in Rahul's work — none of this was ever asked of him:

In the documentBuilt?Note
187-metric catalogue with sensitivity tiersNo Ten metrics shipped. The other 177 are a roadmap, not a shortfall.
Screen time as a self-set budgetNo Genuinely clever — scored as "stayed under my own budget", never app names. Nothing built.
FFH-native rules — Bingo squares, tracker entries, streak payoutsNo These are ours to build, not Rahul's — they do not touch health data at all.
Phase 2 — Apple depth layer (Time in Daylight, Walking Steadiness, Six-Minute Walk)No Still coins-only, still no health data to us. Sequenced after Phase 1 is trustworthy.
Phase 3 — clinical opt-in, member shares detail with their own clinicianNo Separate service, separate database, separate consent. Rob's "Wall". This is the phase that needs the signed BAA — not Phase 1.
Saved