Appearance
Consumer release build — reconciliation against the latest design (2026-09-04)
⚠ THIS IS A LOG. IT RECORDS WHAT WAS TRUE ON 2026-09-04, AGAINST THE DESIGN PULLED LIVE THAT DAY.
Design state was read from the Claude Design prototype project through DesignSync, never a local cache: SCREENS.md (ConsumerHome at round 40), ConsumerHome.dc.html, MyQRSetu.dc.html, Biodata.dc.html, BiodataView.dc.html, Account.dc.html, Notifications.dc.html, ScanVerify.dc.html, setu-card/BiodataPage.dc.html, consumer-data.js, biodata-core.js, qr-registry.js, qr-verify.js, my-qrsetu/biodata.spec.md and my-qrsetu/Integration.dc.html. Repo state was measured from apps/mobile, packages/*, supabase/migrations and the parity contracts, by reading the files. Do not edit this forward; run a new one.
Owner's brief (2026-09-04): a consumer build that is functionally complete for ConsumerHome · Marriage Biodata · Consumer Profile · Consumer Settings · the core flows that make those run end to end, ready for release, without expanding marketplace functionality. Upcoming planned change: the bottom bar's Orders → Meetings; build no new dependency on Orders.
0 · The finding that reorders the work
🔎 THE MARKETPLACE IS OFF BY DESIGN DEFAULT, AND OFF MEANS ABSENT — WHICH REMOVES HALF OF HOME
SCREENS.md (round 40): "The marketplace is conditionally OFF, and off means ABSENT: platform.capability.consumerMarketplace (default false, Mission Control) gates location + search, the action strip, featured, trending, the category mosaic, saved and recent, the order book and shop scans. No 'coming soon' tile ever stands in for them." consumer-data.js confirms it: homeSections(present, { marketplace }) drops every section flagged market: true when it is off.
Two consequences, both in the owner's favour:
- The consumer release build needs NO marketplace backend at all. Item feed, vendor feed, saved store, area picker, category taxonomy and the platform capability table — every one of the
blockedandgaprows on the currentconsumer-home.jsoncontract that named them — falls out of scope for this release by the design's own switch. That is exactly the owner's instruction restated as configuration. - The current
ConsumerHomeScreenis not "21 of 39 rows" — it is the wrong shape. It renders the round-16 discovery stack (search · actions strip · featured · near you · the QR tools row), and round 40 retired the QR tools row and the action strip "as duplicate navigation". Below the identity card, almost nothing currently on the screen survives into the design being shipped. The rebuild is the identity hub, and it is the first client task.
What round 40 puts on Home, in order (HOME_SECTIONS), with the marketplace off:
| Section | Reads | Backend it needs |
|---|---|---|
| identity (pinned) | greeting · address + branded QR + copy · pulse chip (N need you / N live) · Share my card · My QR setu · start block when nothing is published | get_my_slug ✅ · biodata access rollup ❌ |
| stories — "Your QR experiences" | one ring per activated experience, state from personalStories(); dashed Make new | biodata record ❌ |
| focus — "Waiting on you" | snap carousel of ownerPrompts(): a request waiting, a release lapsing, a removal being honoured | biodata shares / requests / removal ❌ |
| today | the next accepted session · daily check-in · unread coach announcement | meetings ❌ · progress ❌ — not this release |
| quickMake — "Make in one tap" | Wi-Fi · UPI · link · photos, from FREQUENT_MAKERS | none (client-only makers) |
| progress | the profile journey: journey() percentage ring, four milestones, thinnest section | biodata record ❌ |
| yourCards — "Your QR setu" | the creation cards with access facts (never scan counts) | biodata record ❌ |
| create | a brand-plate lead card for the first kind, staggered tiles | none |
| weekRecap | — | meetings / progress ❌ — not this release |
1 · Screen-by-screen reconciliation
Verdicts: ✅ built and matches · 🟡 partial · ❌ missing · ⛔ blocked (a dependency that must land first, named).
1.1 The chrome — the tab bar, the centre button, the header
| Element | Design | Implementation | Verdict |
|---|---|---|---|
| Bottom bar | CONSUMER_TABS: Home · Chats (unread badge) · [centre] · Saved · Orders; Account is a header avatar, not a tab; consumerBarTabs() is the one place the two-and-two split is decided | No tab bar exists. app/consumer/_layout.tsx is a plain Stack (it was created on 2026-09-03 solely to host the app lock) | ❌ |
| Centre button | opens the More sheet: three groups from consumerMoreGroups() — Make something (personal kinds) · QR tools (CONSUMER_QR_MAKERS) · Tools (Scan · My order code · Recently scanned · Share my contact) | none | ❌ |
| Header | wordmark · clock (reminders sheet, count) · bell (notifications, unread count) · avatar (Account) | none on Home | ❌ |
| Orders tab | present in the design; owner: to become Meetings | OrderCode exists as a screen; no tab | — reserve the slot, build nothing new on Orders |
This is the single biggest reachability gap. Nine consumer routes exist and nothing navigates to them (QRS-730's shape, still true one layer up). Every screen below is unreachable until this lands, so it is W3, immediately after the schema.
1.2 ConsumerHome
Covered in §0. Of the identity card itself: greeting ✅ · address ✅ · branded QR ✅ · Share ✅ · claim sheet ✅ (a stopgap, correctly recorded) · copy control ❌ (expo-clipboard not installed — needs the size callout) · pulse chip ⛔ · My QR setu second action ⛔ · start block ⛔ — the three blocked ones all read the biodata record.
1.3 My QR setu — MyQRSetu.dc.html
7 states: Open · In discussion · Concluded · Nothing activated · Address just claimed · Loading · Error. Implementation: none. Structure: identity card (initials, name, address + copy, QR, note, Share my card, gear → Account) · the Intro-card row · Activated (the biodata card: title, address, status chip + lifecycle chip, owner line, three access facts with the line "Access facts, not attention. QR setu does not count views on a person", four actions) · Available (Invitation · Birthday card, locked "On a plan · Managed on qrsetu.com" — which is the fifth rule applied correctly: discoverable, locked, no in-app CTA) · Your identity settings rows → Account views.
Everything except the Activated card and the Intro-card row is buildable with what exists today.
⚠ THE DESIGN HAS REVIVED A RETIRED PRODUCT NAME, AND THIS PAGE HAS TO WRITE AROUND IT
MyQRSetu.dc.html links to a screen the design project calls the Intro card and files under a name containing the word this repo retired on 2026-07-23 (QRS-172) — the check:docs vocabulary gate's term group #1. Its PERSONAL_KINDS id is intro, and its public page is setu-card/BioLinkPage.dc.html. This page refers to the feature only as the Intro card, and the collision is logged as QRS-1007 so the design project can be corrected rather than the repo's gate weakened. It is not in the owner's five priorities and is classed as a later phase below.
1.4 Marriage Biodata — Biodata.dc.html, the editor and the access view
One module, two views on ?view=: content (10 states: empty and starting · partly complete · complete · editing a live profile · validation on a required field · saving · saved · loading · could not save · read-only for a co-manager) and people (8 states: nobody yet · a basic link shared and opened · a request waiting · released people with expiry dates · an expiry approaching · a release withdrawn · a subject removal request · concluded, ready to reopen). 12 sheets: conclude · custom · field · opening · people · photo · picture · release · reopen · script · share · tier. Subject prop: Sister (owner is not the subject) · Myself — every string forks on it through words().
The domain behind it, measured from biodata-core.js:
| Fact | Value |
|---|---|
| Field registry | 60 fields in 9 groups (about 11 · work 6 · family 10 · community 4 · kundli 9 · expect 12 · talk 4 · contact 4, plus the custom group more) |
| Tiers | basic (anyone with the link) · released (approved one by one, dated, revocable) · private (never shared, structurally unreleasable) |
| Required | firstName · gender · age (derived from dob) · marital · city · education · profession · dob · phoneNo — the last two are private |
| Enum fields (product vocabulary, rendered per language) | gender · marital · diet · bloodGroup · manglik · nakshatra · charan · gan · nadi · familyType · two expectation pickers |
| People | values.people[] of { id, relation, name, detail, seniority, order }, max 10; relations father · mother · brother · sister · mama · self; four family layouts (tree · vine · cards · list) |
| Photographs | max 4, ordered; the cover is the only one a forwardable link shows, served cropped; the rest wait for a release; no download control anywhere |
| Opening | { on, emblems: [] }, up to MAX_OPENING; emblem = image or words or both; scripts shipped: Devanagari, Latin |
| Custom fields | max 8, 6 types (text · long · number · date · yesno · items), 5 presentations, label ≤ 28 chars, conflictFor() refuses a label that repeats a standard field, up to 3 lead chips |
| Access | RELEASE_DAYS 90 · EXPIRY_WARN_DAYS 10 · REMOVAL_HOURS 72 · PLAN { subjectCap: 1, personLinkCap: 6 } |
| Lifecycle | CREATION_STATUS draft · live · ended, with life a sub-state of live: open · discussion · concluded |
| Languages | mr · hi · en; the UI is multilingual, the data is never translated (formatValue() may touch only ENUM_FIELDS) |
| Lift contract (the design's own storage hint) | profile_field_visibility (profile_id, field_id, hidden) · profile_field_tier (profile_id, field_id, tier) · profile_photo (profile_id, id, position, is_cover, shown) · profile.theme_id |
Implementation: none. No table, no RPC, no Edge Function, no seam, no schema, no screen. ⛔ on plan items 1.5–1.12 and 2.1–2.6, every one of which is still open.
1.5 Marriage profile, read in the app — BiodataView.dc.html
Props: viewer (A family you released · Anyone with the link · Owner preview) · screenState (Ready · Loading · Network error · Link withdrawn · Search concluded) · subject · familyLayout. Sheets: ask (a signed access request) · menu · share. The design's one rule: "WHAT A VIEWER MAY SEE IS DECIDED IN biodata-core, never in a screen" — shownFields(), visiblePhotos(), publishedCustom(). Implementation: none. ⛔ on 2.2 (the token-scoped public read).
1.6 The public page — setu-card/BiodataPage.dc.html (web)
9 scenarios: basic with one cropped photograph · basic text only · released with photographs · request submitted and pending · link expired · link withdrawn · concluded · removal requested (subject view) · loading; plus a WhatsApp link preview view that is photo-free by rule. noindex, no-store, in the owner namespace at /<slug>/biodata and /<slug>/biodata/<share>. Implementation: none. apps/web/src/app/routes.ts has no :slug/biodata route, and :slug itself is a 301 to the Setu Card for every owner kind — so a consumer's address currently redirects into a card route that will 404, which is the enumeration oracle decision D5 exists to close. ⛔ on 2.2 and Phase 5. ⚠ Without this page, every share control in the app hands out a dead link, so it is in the release build, not after it.
1.7 Account — Account.dc.html
| View | Design | Implementation |
|---|---|---|
| hub | avatar + name + email · guest vs Confirmed account chip · Saved / Orders / Scans counters · Edit profile · four ACCOUNT_GROUPS (Personal: My QR setu · Personal details · Your areas · Your contact code — Your activity — Preferences — Support) · create-your-own-Setu-Card CTA · sign out · version | 🟡 six flat rows (no groups, no My QR setu row, no profile card, no counters, no sign-out); the guest banner is shown to every visitor including a signed-in one |
| details | name · mobile · email with live validation · change photo · delete account behind a confirm | ❌ (setDisplayName and manage-account update_email / delete_account exist server-side) |
| areas | the areas you browse, current marked | — absent with the marketplace off |
| notifs | channels · topics · quiet hours; orders/payments locked ON with the reason | ✅ (built against the prefs seam) |
| appearance | theme · language · rupee note | ❌ (themeStore + localeStore already hold both) |
| privacy | what is on this phone · clear · download my data | ❌ |
| help | accordion FAQs · message support | ❌ |
| about | wordmark · positioning · version · legal | ❌ |
| accountState | Registered · Guest · Loading · Error | 🟡 loading only |
⚠ The design persists preferences to qrsetu_consumer_prefs by merge, which the existing consumerPrefsService already does. The hub's Sign out must call the same useSignOut teardown the merchant uses (it clears the device PIN since 2026-09-03) — do not write a second sign-out.
1.8 Notifications — Notifications.dc.html
✅ Built as a derived list with Today / Earlier groups, read state, Mark all read, empty state. 🟡 The design now carries three biodata kinds (biodataRequest · biodataRemoval · biodataExpiry) and a Notification preferences link to Account?view=notifs; our CONSUMER_NOTIFICATION_KINDS has five kinds and none of the three. ⛔ The three read the biodata access rollup. ⚠ The design flags its own read state as a prototype shortcut: "On lift it must be PER ACCOUNT on the server: someone who reads a notification on their phone must not find it unread on the web an hour later." Ours is per device by deliberate seam design. Decision owed — QRS-1011.
1.9 Scan and verify — ScanVerify.dc.html
Design: camera view (always dark) · denied state · a QR setu code opens, it does not get reviewed (registry resolve → half-second label → push the owning screen) · wrong-audience sheet · the four-verdict sheet for anything not ours (verified · unknown · caution · danger, signals in plain words, payee card for UPI, business card, scope note) · report sheet with five reasons. Logic in qr-registry.js (a data table: order · item · order_receipt · biodata_share · biodata · identity · setu_card, biodata entries deliberately above setu_card) and qr-verify.js.
Implementation: apps/mobile/src/ui/scanner/ holds the whole camera shell (ScannerScreen, CodeScanner, ManualCodeEntry, useCameraAccess) built for both scan screens — and it has zero importers outside its own folder. There is no /consumer/scan route, and two of the four QR-tool entries in @qrsetu/domain point at it, so they are live dead links. The ledger already marks scan-verify missing. ⚠ The registry's identity matcher needs an owner-kind lookup (setOwnerKindLookup) that the design leaves unwired — "a person's identity slug still resolves as a Setu Card" (QRS-914). The slugs registry's owner_kind column is exactly that answer and now exists; it needs one RPC to expose it.
1.10 Everything else the design has, classified
| Screen | State | Class |
|---|---|---|
Chats (Chats.dc.html, rounds ≤ 22 built; 23 media + 24 message-level interaction not built) | 🟡 | keep as is for this release |
| OrderCode · ItemFeed · VendorFeed · ItemView · VendorView · Featured | ✅ built | not reachable from Home with the marketplace off — keep, do not expand |
| MySessions (the Meetings tab's future destination: list · calendar · join · reminders) | ❌, no meetings schema anywhere in the repo | later; reserve the 4th tab slot |
| MyProgress (the retention surface for the direct-seller vertical) | ❌ | later, not in the owner's five |
Quick makers: LinkQR · WifiQR · UpiQR · PhotosQR (+ place · event · doc · social · profile in CONSUMER_QR_MAKERS) | ❌ | later; link / Wi-Fi / UPI are pure client (encode + PNG + share) and cheap once the chrome exists — see the UPI decision below |
| Intro card (§1.3 warning) | ❌ | later; its My QR setu row renders as not ready meanwhile, never as a dead link |
| Onboarding · PIN / app lock | ✅ in code | device pass still owed (cases 53–66) |
2 · Backend and dependency gaps that block the client
Measured on the repo, 2026-09-04. ✅ exists · ❌ absent.
| # | Gap | Plan item | State | Blocks |
|---|---|---|---|---|
| B1 | biodata_subjects · marriage_biodatas · shares · access requests · removal · RLS · one-active-per-subject partial index | 1.7 | ❌ zero biodata references in any migration | Home stories/focus/progress/yourCards · MyQRSetu activated card · the whole editor · notifications' three kinds |
| B2 | family_members / people as jsonb objects, never a delimited string | 1.12 | ❌ | editor family group, all four layouts |
| B3 | media_scope_exactly_one widened to three-way (owner_user_id) | 1.5 | ❌ two-way today (20260814100000:73) | photographs, avatar, own-picture emblems |
| B4 | private R2 bucket wired; manage-media stops hardcoding bucket: 'media' (index.ts:247) | 1.6 | ❌ | every consumer photograph (a public bucket makes revocation impossible — D4) |
| B5 | feature_grants row capping subjects at 1 | 1.8 | ❌ | the plan line on MyQRSetu, the create sheet's cap |
| B6 | profile reference: bigserial + Feistel in the EF, reference bigint unique | 1.10 | ❌ | the number shown on every surface; irreversible after launch |
| B7 | biodata_templates sibling table + retire guard, template_key/version on the record, no FK | 1.11 | ❌ | lossless template switching; irreversible after launch |
| B8 | pgTAP: a consumer reads nothing merchant-owned; an anon token read returns only its tier | 1.9 | ❌ | release (CLAUDE.md requires it now that authenticated means the public) |
| B9 | manage-biodata Edge Function (create · edit · publish · release · withdraw · conclude · reopen · remove) | 2.1 | ❌ | every write |
| B10 | token-scoped public read RPC | 2.2 | ❌ | BiodataView · BiodataPage · the share links |
| B11 | rate limit on the anonymous read | 2.3 | ❌ grep rate_limit over migrations and _shared returns nothing | release (QRS-921) |
| B12 | subject notification over WhatsApp on publish (D3) | 2.4 | ❌ (the channel exists: send-auth-otp's core) | publish |
| B13 | Zod schemas + packages/data seam with a real impl bound in the barrel | 2.5 | ❌ | every screen; build the seam first so screens start against the stub |
| B14 | cache purge on write | 2.6 | ✅ invalidateCardCache pattern exists | reuse |
| B15 | manage-account soft delete (users.status='deleted', keeps reclaim_hmac) | 1.4 second half | ❌ hard-deletes today (QRS-909) | the account-deletion row in Account › details |
| NEW-1 | owner-kind lookup RPC over slugs.owner_kind (for qr-registry's identity matcher and the web /:slug greeting) | not in the plan | ❌ | ScanVerify's identity route · D5 |
| NEW-2 | /:slug byte-identical greeting for a person (D5) and /:slug/biodata[/<share>] routes in apps/web | Phase 5 (5.1–5.3) | ❌ :slug is a 301 to the card for every owner | every shared link |
| NEW-3 | the platform capability consumerMarketplace | not in the plan | ❌ no control exists | for this release a single domain constant, read through one function, defaulting false — the honest form of the availability axis for an unshipped capability; promoting it to a platform-control row is a later, separate decision |
| NEW-4 | notification read state per account | not in the plan | device-local today | decision QRS-1011 |
| NEW-5 | expo-clipboard for the address copy control | not in the plan | ❌ | owes the size callout before install (CLAUDE.md); the share sheet already offers Copy on both platforms, so it is a nicety with a cost |
⚠ B6 and B7 are the two that are cheap today and expensive after the first real family publishes. The plan says so and it is still true: a reference format ends up on printed cards and in people's phones, and versioning retrofitted after templates exist is a migration.
The schema shape B1 needs — stated here so 1.7 is not designed twice
Two prior findings constrain it and they pull in opposite directions until you read them together: the build assessment's C2 applies ADR-0010's split rule (anything the platform FILTERS, SORTS, GROUPS, CHARTS, PRICES or GATES on is a typed column), and the design's own LIFT_CONTRACT hints at per-field tier and visibility rows. The registry has grown from ~40 to 60 fields across rounds 7, 8 and 9, adding fields in each round.
Recommended: typed columns for everything the platform gates or filters on — owner_user_id, subject_id, slug, status, life, reference, template_key, template_version, family_layout, content_language, published_at, concluded_at; and jsonb bags keyed by the registry's field ids for the content — values, field_tiers (overrides of the registry default), hidden, people, photos (ordered media ids with cover/shown), opening, custom_schema, custom_values. Nothing in the product filters on a field value, so the split rule is satisfied, and a design round that adds a field is a registry change, not a migration. The public RPC is the only place tier resolution may happen (C2's own caveat). Shares, requests and the removal are their own tables because they are gated and queried on. This is a recommendation for 1.7's migration header to argue against, not a decision — it is written down so the argument happens once.
3 · Release build versus later — the line
In the consumer release build:
| Why it is in | |
|---|---|
| Tab bar · centre button · More sheet · header (bell · clock · avatar) | nothing else is reachable without it |
| Home identity hub (round 40, marketplace off): identity · stories · focus · progress · yourCards · create | the owner's item 1 |
| My QR setu | the identity home the design routes everything through |
| Biodata editor + people and access, with share | the owner's item 2 |
| BiodataView (owner preview · recipient in the app) | the design's "see it as a family sees it", and the in-app recipient |
BiodataPage on the web, at /<slug>/biodata | without it every share link is dead; the WhatsApp preview is photo-free by rule |
| Account: hub · details · appearance · notifs · privacy · help · about (areas absent) | the owner's items 3 and 4 |
| Notifications with the three biodata kinds | already built; the kinds are one derivation |
| ScanVerify, basic: registry resolve → open; verdicts for our own namespace; no reports and no code-status until those have a backend, and the sheet says so | the owner named scanning; the /consumer/scan dead link is a live defect |
| Subject notification over WhatsApp (D3) | a publish that tells the subject nothing is a fiduciary gap |
| mr · hi · en for every new leaf | QRS-924 — Marathi-first, launch-blocking |
| Signed APK · privacy policy and terms · Sentry DSN | 6.3 · 6.4 · 6.5, all still open |
Later, deliberately: the Intro card · quick makers · MySessions / Meetings tab · MyProgress · Chat rounds 23–24 · marketplace ON · per-recipient link analytics · push · today / weekRecap sections.
4 · Recommended execution order
Sequenced by irreversibility first, then by what unblocks the most. W1–W2 are design-independent and run in parallel with W3–W4 (the plan's own thesis: screens compose against interfaces that exist and are tested).
| Wave | Work | Unblocks |
|---|---|---|
| W1 · Irreversibles | 1.4 soft delete · 1.5 media XOR · 1.6 private bucket · 1.7 + 1.12 schema (shape in §2) · 1.8 grant · 1.10 reference · 1.11 templates · 1.9 pgTAP · NEW-1 owner-kind RPC | everything |
| W2 · Backend surface | 2.5 schemas + seam first (client starts against the stub) · 2.1 manage-biodata · 2.2 public read · 2.3 rate limit · 2.4 WhatsApp · 2.6 purge · NEW-4 if decided | all writes and reads |
| W3 · Chrome | consumer _layout tab bar + centre button + More sheet + header · NEW-3 capability constant · route every existing consumer screen | reachability of every screen |
| W4 · Home | identity card completion (pulse · My QR setu · start block · copy if NEW-5 approved) · stories · focus carousel · progress · yourCards · create sheet | the owner's item 1 |
| W5 · My QR setu | all 7 states · share sheet · Available (locked) · Your identity rows | the identity home |
| W6 · Biodata content | the editor: 9 groups · 60 fields · people sheet · photos · opening · custom fields · 10 states | the owner's item 2 |
| W7 · Biodata people | shares · requests · release with expiry · withdraw · removal · conclude / reopen · celebration · 8 states | access |
| W8 · BiodataView | 3 viewers · 5 states · ask · share | preview and in-app recipient |
| W9 · Account | profile card · groups · details · appearance · privacy · help · about · sign out via useSignOut | items 3 and 4 |
| W10 · Notifications + Scan | three biodata kinds · /consumer/scan on the existing scanner shell · registry as a domain module · basic verdicts | the dead links |
| W11 · Web | /:slug/biodata[/<share>] · /:slug consumer greeting (D5) · headers export (noindex · no-store · Cache-Tag) · photo-free OG | every shared link |
| W12 · Ship | i18n leaves in three languages (Marathi human-reviewed) · parity contracts with reachableFrom on every new route · device suite cases · signed APK · privacy/terms · Sentry · a fresh iOS build | release |
⚠ Every screen in W4–W10 gets a parity contract enumerated from the design's own states before it is called done (the fourth rule), and every route-rendered scenario carries reachableFrom — the rule added on 2026-09-03 because a green contract covered an unreachable PIN gate for a month.
5 · Decisions owed before the wave that needs them
| # | Decision | Needed by | Recommendation |
|---|---|---|---|
| D-a | Marketplace OFF for the consumer release | W3 | Yes. It is the design's default and the owner's brief. Saved and Orders render the design's honest empty states ("Saving shops arrives with the marketplace") |
| D-b | The 4th tab while Orders → Meetings is pending | W3 | Keep the bar 2 + centre + 2 with Orders showing its honest empty state, and put no new code behind it; swap the destination to MySessions when the meetings schema exists |
| D-c | Notification read state: per device (ours) vs per account (the design, "on lift") — QRS-1011 | W2 | Per account; one small table, and the web will otherwise disagree with the phone |
| D-d | Personal UPI QR maker (CONSUMER_QR_MAKERS.upi) vs the standing rule no UPI promotion, no vendor UPI ID — QRS-1009 | later (not in this release) | The rule was written about vendor payment; a person's own UPI code is a different thing. Decide it, do not let it slide in with the makers |
| D-e | PDF export: decisions §6 records "a deliberately limited PDF export exists" (round 1); the design's share sheet now says "No export, and it is stated. No PDF and no image" — QRS-1010 | W7 | Follow the later design (no export); it is the stronger privacy posture and the share sheet already states it |
| D-f | Biodata URL: /<slug>/biodata (decisions §4 left it open; the design has since built on it, and biodata is a reserved slug) | W1 | Confirm the design's answer |
| D-g | Minimum age (decisions §4) | W6 | Owner decision; the dobRange in biodata-core carries an AGE_FLOOR |
| D-h | Moderation of an uploaded emblem or photograph — post-report, remove the emblem never the profile | W6 | As recommended in the readiness log (B3) |
| D-i | expo-clipboard for the copy control (NEW-5) | W4 | Owner's size call; the share sheet already offers Copy |
6 · What this reconciliation cannot see
- Whether the enumeration is complete. It is a human read of one design pull and one repo, and it finds what it looked at. The parity contracts written in W4–W10 are the falsifiable form.
- Visual fidelity. Nothing here judges spacing, hierarchy or whether a family will trust the page.
- The device. The auth and app-lock work from 2026-09-03 is proven by 1,101 unit tests and by nothing on hardware; the same will be true of every screen here until the device suite runs.
- Production. Every measurement is against the repo and Dev.
No code was changed for this reconciliation, and no merchant or enterprise file was read for modification.