Date: 2026-06-11 · Auditor slice: V1 Product Promise + Customer Web + Customer
Mobile + Shared Consumer Shell + Public Web and Distribution. Method: static
source reading + grep only; every delegation chain followed to the bottom; all
06-10 ground-truth fixes (A–E phases) treated as landed and NOT re-reported.
Accepted postures (D1 preview register on registry-covered surfaces, C3
guardedFixtureRoute dev-only fixtures, E5/E7 retirements, env-gated
fail-closed providers) are excluded per the brief.
P0-HONESTY — fabricated data / fabricated success on live paths#
1. Home "Daily plan" is a permanent unlabeled simulation while a real routines backend sits unused#
Severity: P0-HONESTY Evidence:
apps/oshun/web/src/components/home/HomeWorkspace.tsx:496—<DailyPlanV2 />mounted with no props.apps/oshun/web/src/components/routines/DailyPlanV2.tsx:1071-1072—const routines = propRoutines ?? SIMULATED_TODAY_ROUTINES; const recommendation = propRecommendation ?? SIMULATED_RECOMMENDATION;DailyPlanV2.tsx:172-260—SIMULATED_TODAY_ROUTINES(userId: 'user_sim', frozentodayDate = '2026-05-24', "Quick Morning Start" with completion state) andSIMULATED_RECOMMENDATION.- Real backend exists and is reachable:
apps/oshun/bff/src/routes/routines.ts:110-407(GET/POST /v1/routines, templates, recommendations, executions) and typed hooks atapps/oshun/web/src/lib/hooks/use-bff.ts:2226-2271— zero callers on home. Spec promise: features.md:318-319 (redesigned dashboard reflecting the V1 home model); features.md:260 (coherent product, not fabrications). What the code does: every member's home shows the same fabricated routine list and progress bar with no fallback/preview disclosure of any kind — not even the "Curated …" pill the other home sections use. This is the C15 fixture pattern, alive on the highest-traffic surface, and the orphaned-engine pattern (tested backend pointed at nothing) at once. Fix sketch: WireDailyPlanV2throughuseUserRoutines()/useActiveRoutineExecution()/useRoutineRecommendations(); honest empty state ("No routines yet — create one") when the member has none; deleteSIMULATED_TODAY_ROUTINESfrom the live path (keep as test fixture only).
2. /profile + /settings fabricate "Domain statistics" and "Connected services"; the Connect/Manage button is dead#
Severity: P0-HONESTY Evidence:
apps/oshun/web/src/components/ProfileSettingsPanel.tsx:106-143—DEMO_DOMAIN_STATS(Tara 42 sessions/315 min/7-day streak, Veritas 89 sessions, "Top action: Breathwork" …).ProfileSettingsPanel.tsx:157-167—DEMO_SERVICES: "Google — Connected · 2 hours ago", "Apple Health — Connected · 30 min ago".ProfileSettingsPanel.tsx:1105— section subtitle computes "199total sessions" from the fixture;:1120renders the fixture grid;:1448"2 connected";:1454fixture list.ProfileSettingsPanel.tsx:1495-1512— the per-serviceConnect/Manage<button>has noonClick— a dead control.- Mounted live at
app/profile/page.tsx:90andapp/settings/page.tsx:35. Spec promise: features.md:401-403 (profile/settings for account, billing entry, memory controls …); features.md:269-270 (make state visible where it affects user trust). What the code does: every user is told they have 199 sessions of cross-domain history and two live OAuth integrations syncing their data. Both claims are fabricated for everyone; the integration buttons do nothing. Fix sketch: Delete both DEMO_ blocks. Domain statistics: derive from the real/v1/activity+ achievements reads the Activity surface already uses (or render the honest "no stats yet" note). Connected services: render the real calendar-connections client (profile/calendar-connections-client.ts) plus an honest "no integrations connected" empty state; remove the dead button or wire it.
3. Billing is a client-side simulation: every user seeds as paid "Pro" with a Visa and a paid invoice, and "purchase" fabricates success#
Severity: P0-HONESTY (with a P1 entitlement-coherence edge) Evidence:
libs/oshun/auth/src/billing-store.ts:976-1025—createDefaultOshunBillingSnapshot()seedscurrentPlan: 'pro',accountStatus: 'active', payment method "Visa ending in 4242", and one paid $12.00 invoice dated now.apps/oshun/web/src/profile/store.ts:58-61— billing store built onlocalStoragewith that seed and no BFF fetcher (compare the consent/export/deletion stores in the same file, which do have fetchers).lib/auth-context.tsx:145onlyclear()s it on sign-out — which re-seeds the same fiction (billing-store.ts:929).apps/oshun/web/src/components/profile/BillingSection.tsx:113-135—handlePurchaseClick→oshunWebBillingStore.purchase(...)(a localStorage mutation; no payment provider, no server call) then reports "<plan> active · $X/mo · renews <date>" andsyncProfilePlan(targetTier)(:1472-1474) flips the client profile plan.apps/oshun/web/src/components/billing/ShellFeatureGate.tsx:46-47— client feature gates resolve entitlements from that client-mutable profile plan.BillingSection.tsx:280-291,651— "Report failed charge" button callssimulateBillingFailure()which injects a fabricated decline into the local store instead of reporting anything.- Same seeds on mobile:
apps/oshun/mobile/src/profile/store.ts:21-41(in-memory storage, samecreateDefaultOshunBillingSnapshot), consumed byapp/(tabs)/profile.tsxviagetLatestBillingInvoice/getDefaultPaymentMethod. - Two sources of truth: the real plan lives server-side in
customerAuthStateStore(A6 entitlement middleware; C10 settlement flips it) and is never reconciled into this surface. Spec promise: features.md:401-402 (billing entry in profile/settings); features.md:260 (coherent product). What the code does: a free user opens Billing and sees an active paid Pro subscription, a card on file, and a paid invoice — none real. Clicking "purchase" fabricates a successful subscription without moving money or touching the server plan, then unlocks client-side feature gates. The crypto path (quote→settle, C10) is real and entirely separate — the two billing stories contradict each other. Fix sketch: Give the billing store a BFF fetcher like its siblings:GET /v1/billingderiving plan from the session's persisted plan (A6) + real invoices from the C10 invoice store; seed honest-empty (free, no methods, no invoices). Purchase buttons route into the real payment flow (crypto quote) or an honestnot_configuredstate. DeletesimulateBillingFailureor rename/rewire it to a real support intake.
4. Fabricated profile-stats seed (7-day streak, 18 saved items, 5 active domains) reaches Home and Profile for every signed-in member#
Severity: P0-HONESTY Evidence:
libs/oshun/auth/src/profile-store.ts:240-258—createDefaultOshunProfiledefaultsstats: { streakDays: 7, savedItems: 18, activeDomains: 5 },plan: 'pro',verified: true.apps/oshun/web/src/lib/auth-context.tsx:530-545—syncProfileStoretakes identity/plan from the real session but passesstats: undefinedfor a new user → fabricated defaults persist.- Rendered:
components/home/HeroBanner.tsx:457,1003("{streakDays} day practice streak"),components/ProfileSettingsPanel.tsx:307-309,950("Day streak" stat tile). - Mobile mirror:
apps/oshun/mobile/src/auth/mobile-auth-context.tsx:223-235— same pattern, plus fallbacksplan ?? 'pro',verified ?? true. - Only
savedItemsis ever reconciled to reality (lib/library/webLibraryStore.ts:270-287);streakDays/activeDomainshave no real writer anywhere. Spec promise: features.md:318-319 (home reflects the V1 home model); the C2/C3 ground-truth fixes made the Arete streak real — this is a second, contradicting streak. What the code does: a brand-new member's hero banner congratulates them on a 7-day practice streak they don't have; the same fake number sits beside the now-real Arete streak from/v1/arete/streak— two sources of truth, one fabricated. Fix sketch: Seed stats at honest zero; derive streak from the real/v1/arete/streak(or the achievements stats adapters) and activeDomains from real domain activity; never default plan to 'pro' or verified to true when the session doesn't say so.
5. Web notifications center fabricates notifications whenever the live feed is empty — including a fake billing alarm#
Severity: P0-HONESTY Evidence:
apps/oshun/web/src/components/NotificationsCenterPanel.tsx:1036-1038—setItems(mapped.length > 0 ? mapped : buildInitialNotifications())on success-but-empty, and the same fixture in thecatch.NotificationsCenterPanel.tsx:207-260—buildInitialNotifications(): "Cross-domain handoff is ready", and "Billing review needs your confirmation — Support flagged a renewal mismatch on your Veritas upgrade" with a deep link into the billing upgrade flow. Spec promise: features.md:399-400 (notification center behavior for mixed-domain, admin, support … events); features.md:428-429 (honest loading/empty/degraded states). What the code does: a new user with zero notifications is shown fabricated unread items by design (not just on outage), one of which is a fake billing problem that funnels them toward the (also fake — finding 3) upgrade surface. No disclosure. Fix sketch: Empty feed → honest empty state ("You're all caught up"). On fetch failure → disclosed unavailable state. DeletebuildInitialNotificationsfrom the live path.
6. Home ActivityFeed serves fabricated first-person activity on outage#
Severity: P0-HONESTY Evidence:
apps/oshun/web/src/components/home/ActivityFeed.tsx:76-110 —
FALLBACK_ACTIVITY: "Completed morning breath sequence" (24 min ago), "Saved
'AI regulation frameworks' to reading queue", "Logged ISS visibility
observation", "Completed daily check-in"; served at :465, :494, :526
whenever /v1/activity errors or returns no items array, with only a small
notice ("Home kept its fallback entries"). Spec promise: features.md:395-396
(cross-domain activity timelines); features.md:284-285 (degrade safely);
features.md:428-429. What the code does: exactly the silent-fixture pattern
C15 deleted from /activity — the home strip was missed. The outage notice
exists but the content remains first-person fabricated history with live "x
min ago" timestamps. Fix sketch: Replace the fixture fallback with the same
honest unavailable presentation /activity now uses (empty list +
CustomerShellOutageBanner reason). Delete FALLBACK_ACTIVITY.
7. Home mixed-domain recommendations swap in SIMULATED_CROSS_RECOMMENDATIONS on error or empty, with fabricated personal context#
Severity: P0-HONESTY Evidence:
apps/oshun/web/src/components/home/MixedDomainRecommendationsLane.tsx:61-62,109—isUsingFallback = isError || !hasLiveRecommendationPayload; thenrecommendations={isUsingFallback ? SIMULATED_CROSS_RECOMMENDATIONS : …}. Disclosure is an 11px "Curated shell mix" pill.components/cross-domain/CrossDomainRecommendations.tsx:124-186— fixture items claim "The centering session you finished this morning", "Your focus goal for the week", "The breathing reset you just completed" assourceContext.CrossDomainRecommendations.tsx:944,957-962—useDefaultFallback = trueby default: ANY consumer passing an empty list silently gets the fixture.- The fallback also bypasses
selectHomeMixedDomainRecommendationSlate— the spec's suppression rules are not applied to what actually renders. Spec promise: features.md:324 (mixed-domain recommendations with reason labels and suppression rules). What the code does: a new user with genuinely no recommendations (empty payload — not an outage) is told a centering session "you finished this morning" points somewhere. Reason labels on fabricated reasons are worse than no recommendations. Fix sketch: Empty payload → honest empty/cold-start invitation (the cold-start module already exists in this file). Error → disclosed unavailable. FlipuseDefaultFallbackdefault tofalse. Keep the fixture only for the (orphaned)CrossDomainHubor delete it.
8. Mobile Activity tab seeds fabricated notifications and never syncs without a dev auth token#
Severity: P0-HONESTY Evidence:
apps/oshun/mobile/app/(tabs)/activity.tsx:41-130—INITIAL_NOTIFICATIONS: "Streak milestone reached — seven consecutive recovery sessions", "Weekly pattern detected — your strongest focus block appears between 9:00-11:00 AM", "Clear-sky window starts soon … in your location".:244,252— rendered as initial state.:422-424—syncNotificationsreturns early if!devAuthToken, so the fixtures stand with no disclosure.:434-437— on fetch failure the message says "Showing local fallback timeline" but the fallback content is fabricated personal insight. Spec promise: features.md:395-396 + 399-400 (activity timeline, notification center); the C16 fix covered mobile home only. What the code does: the mobile activity timeline fabricates behavioral insights ("your strongest focus block") and location claims for everyone whose session token isn't present, and on error. Fix sketch: Initial state empty + loading; unauthenticated → sign-in prompt; failure → honest unavailable (no fixture timeline). DeleteINITIAL_NOTIFICATIONSfrom the live path.
9. Mobile Profile tab: zero network — fabricated "Renata" Iris memories with working forget/export controls, fabricated linked sessions#
Severity: P0-HONESTY Evidence:
apps/oshun/mobile/app/(tabs)/profile.tsx— 0 hits forfetch(/client./api.in 4,092 lines (verified by grep) exceptlistSessionsvia the auth context.:376-470—INITIAL_MOBILE_PROFILE_MEMORY_ENTRIES: "Renata prefers a short breath session before breakfast…", "Renata is comparing Epictetus and Marcus Aurelius…", with fabricated provenance chains ("consent:routines granted by member", audit chain ids) and recall events. EverysetMobileMemoryEntriescall (:1560-1755) is a local mutation of this fiction; there is no hydration from/v1/iris/adapter/review(which C4 wired for web).:267-291,663—INITIAL_LINKED_SESSIONS("iPhone 15 Pro", "Chrome on Mac", "Pixel Tablet" in SF/Austin) is the signed-out state (:893-894resets to it) and the pre-hydration state; the governance fact row reports "Sessions: 3 active" from it (:786-809). Spec promise: features.md:401-403 (memory controls, sessions, devices in profile); features.md:269-270 (memory/consent state visible where it affects trust). C4's whole point was that fabricated memory + pre-granted consent is a trust-surface lie — the mobile mirror was missed. What the code does: mobile members "review", "forget", and "export" memories Iris never stored, about a person who doesn't exist; consent toggles flip local fiction; signed-out users see three fabricated active devices. Fix sketch: Hydrate memory controls from the same/v1/iris/adapter/review+/consentsreads the web uses (typed client already has the BFF base); honest empty + ungranted-consent start. Linked sessions: empty + sign-in prompt when unauthenticated; on error show the error, never the fixture.
10. Mobile Library tab still ships the OLD fabricated Iris handoff (C16 fixed home only)#
Severity: P0-HONESTY Evidence:
apps/oshun/mobile/app/(tabs)/library.tsx:15,36—buildMobileHomeIrisHandoffState()(no args) feedsMobileIrisHandoffCard.src/navigation/mobileIrisHandoff.ts:15-35,61-110—MOBILE_IRIS_CONTINUITYfabricates memory counts (coreBlockCount: 4, workingCount: 7, archivalCount: 18 …), and the builder fabricates items: "Bhagavad Gita 2.47 — 64% progress", "Evidence reflection study path — 68%",issuedAthardcoded'2026-05-06T10:15:00.000Z'.- Contrast:
app/(tabs)/index.tsx+src/network/oshun-bff-client.ts:499-511fetch/consume the REAL durable/v1/iris/mobile-handoffchannel. Spec promise: features.md:339-341 + 411-412 (hand-off and continuity between desktop and mobile). What the code does: the library tab tells every member a desktop reading session is waiting to resume at 64%. Two sources of truth for the same fact (real channel on home, fiction on library), differing within one app. Fix sketch: Point the library tab's card at the same fetched handoff state home uses (lift the fetch into a shared hook); honest "no handoff waiting" when null. DeletebuildMobileHomeIrisHandoffState's fixture path.
11. Mobile "universal sharing" card fabricates active share links and invites; the shell-core engine has no real consumer#
Severity: P0-HONESTY (plus orphaned-engine) Evidence:
apps/oshun/mobile/src/share/mobileUniversalSharing.ts:41-60—buildMobileUniversalShareModel()defaults tobuildDefaultMobileUniversalShareRequests(); summary renders "N/M universal links active".:63-130— fabricated requests: an active library share created 60s ago, an invite tolearner@example.eduwith fabricated rate-limit usage counters.- Rendered on the live library tab:
app/(tabs)/library.tsx:49(buildMobileUniversalShareModel()— no real requests passed). libs/oshun/shell-core/src/universal-sharing.ts(buildConsumerShellShareCenter) has zero runtime consumers besides this fixture wrapper (repo-wide grep) — the real per-link permission/expiry/revocation engine the spec describes is orphaned, while real sharing exists separately inapps/oshun/bff/src/routes/library-sharing.ts. Spec promise: features.md:406-407 (universal sharing, invite, referral flows with per-link permissions, attribution, expiry, revocation). What the code does: tells the member they have live outstanding share links and a pending email invite; "manage" affordances operate on fiction. Meanwhile the real library-share records (BFF) are a second, disconnected truth. Fix sketch: FeedbuildMobileUniversalShareModelfrom the real library-sharing reads (GET /v1/library/...sharefamily) or render the honest empty share center; delete the default fixture requests. Decide the shell-core engine's fate explicitly (wire it over the BFF share store or record an E5-style retirement note).
12. Mobile calendar sync is a simulation end-to-end: fabricated provider connections, static transport, success haptic on a no-op "Sync now"#
Severity: P0-HONESTY Evidence:
apps/oshun/mobile/app/(tabs)/index.tsx:821-823— home card state =buildMobileCalendarSyncState({ issuedAt }), no real inputs.src/calendar/mobileCalendarSync.ts:164-220—buildDefaultMobileCalendarSyncItems()fabricates scheduled rituals/reminders with stale May-2026 dates;:321-346builds fabricated Google/Apple/Outlook connector connections and inbound-change/conflict counts;:588-602—createStaticCalendarTransportis a test double on the default live path (upsertEventechoes the event back as "synced").app/(tabs)/index.tsx:1081-1094— "Sync now" firestriggerHapticIntent('success')and navigates to an activity filter; no calendar API is called. Repo-wide grep: noexpo-calendar, no provider OAuth anywhere in mobile.- Contrast: web calendar connections are wired to real BFF routes
(
apps/oshun/web/src/profile/calendar-connections-client.ts:67-85→routes/calendar-connect.ts,calendar-sync.ts). Spec promise: features.md:371-373 (calendar integrations — Google, Apple, Outlook — with two-way sync where authorized). What the code does: claims three calendar providers are connected and syncing, shows reconciliation counts from a static double, and confirms "sync" with a success haptic without syncing anything. This is fabricated success, not an honest fail-closed seam. Fix sketch: Drive the card from the real BFF calendar-connection reads (same routes web uses); unconnected → honest "Connect a calendar" state; "Sync now" calls the real sync route or is removed. The deterministic reconciliation engine can stay — behind real connector/transport inputs only.
13. Mobile capture: "Request permission" fabricates an OS permission grant; no camera/mic/photo capture exists#
Severity: P0-HONESTY Evidence:
apps/oshun/mobile/app/(tabs)/index.tsx:1126-1130—handleRequestCapturePermission=grantMobileCapturePermission(current, permission)(a local state flip) + success haptic;:1132-1143— tapping a not-ready capture action also just flips the permission to granted locally.src/capture/mobileCaptureIntake.ts— pure model, noexpo-camera/expo-image-picker/expo-av; repo grep shows the only realrequestPermissionsAsyncin mobile is notifications (src/notifications/registration.ts:209). Spec promise: features.md:374-376 (camera, microphone, photo-library capture with explicit permissions and per-domain redaction policies). What the code does: displays "granted" for OS permissions the OS was never asked for, then routes "capture" actions to ordinary screens — no capture pipeline exists behind the card. Fix sketch: Either wire real expo permission requests + a minimal capture→upload leg (the avatar upload asset-store seam from B13 is reusable), or remove the capture card from home and keep the redaction-policy model for V1.x. Never render a granted state the OS didn't return.
P0-STRUCT — structural breaks#
14. 54 standalone /domains/* deep pages bypass the D1 preview banner entirely — including every example the spec names#
Severity: P0-STRUCT (explicitly requested check: surfaces not covered by
DOMAIN_PREVIEW_SURFACES) Evidence:
- The banner mounts in exactly one place:
apps/oshun/web/src/components/DomainRouteExperience.tsx:579, used only by the catch-allapp/domains/[domainId]/page.tsx:91. - 54 concrete pages exist beside it
(
find app/domains -mindepth 2 -name page.tsx):nyx/star-chart,veritas/fact-check,arete/journal,tara/teachers,veritas/claims/[claimId],nyx/events/[eventId], … Each mounts its component directly (e.g.app/domains/nyx/star-chart/page.tsx→NyxStarChart;app/domains/veritas/fact-check/page.tsx→VeritasFactChecker) with noDomainPreviewBannerand no sharedapp/domains/layout.tsx(the only layouts arenyx/rendererandnyx/widgets, unrelated). - Those components are exactly the simulation surfaces D1 labeled for:
components/domains/nyx/NyxStarChart.tsx:19importsnyx-simulation-data;components/domains/veritas/VeritasFactChecker.tsx:52importsveritas-simulation-data; 18 components undercomponents/domainsimport*-simulation-data(repo grep). Spec promise: features.md:303-309 names/domains/arete/journal,/domains/veritas/fact-check,/domains/nyx/star-chart,/domains/tara/teachersas the power-user layer — all four are unbannered standalone pages. What the code does: the registry says tara/veritas/nyx/arete/nisaba are "in preview", but the preview register renders only on the catch-all room; deep links and in-hub entry points land on the concrete pages, where fabricated user data/journalism/scholarship again carries full visual authority — the precise failure D1 was accepted to fix. Fix sketch: Addapp/domains/layout.tsxthat resolves the domain segment from the path and renders<DomainPreviewBanner domainId={…}/>abovechildren(one file covers all 54 pages and future ones); keep the registry as the single switch.
15. Veritas/Nyx/Metis/Nisaba /v1/oshun/* facades were never built — home/feed stages for 4 of 6 domains fail by construction#
Severity: P0-STRUCT Evidence:
apps/oshun/bff/src/adapters/domain-service-adapters.ts:1095-1380+— veritas/nyx/metis/nisaba adapters dial/v1/oshun/briefs/trending,/v1/oshun/events/nightly,/v1/oshun/courses/...,/v1/oshun/saved… against{veritas,nyx,metis,nisaba}BaseUrl.- Repo-wide grep: no
/v1/oshunroute and nooshun-facademodule underapps/veritas,apps/nyx,apps/metis; Nisaba has no service at all. Only Tara (apps/tara/api/src/oshun-facade/) and Arete (apps/arete/api/src/routes/oshun-facade.ts) were built (C1: "Veritas/nyx repeat = follow-up of the same pattern" — the follow-up never happened). - Consumers:
apps/oshun/bff/src/routes/feed-helpers.ts:113-200—/v1/home(web home + C16 mobile home feed) and the feed/continue/favorites stages callapp.domainAdapters.veritas.getTrendingBriefs,nyx.getNightlyEvents,metis.getRecommendedCourses,nisaba.getDailyPassageper request. Spec promise: features.md:265-266 (continuity across web/mobile/home), 364-365 (mobile continuation cards for all six domains), 393-394 (Tara-led home ordering, blended exploration). What the code does: even with every dev service running,domainStatusfor veritas/nyx/metis/nisaba in/v1/homeis permanentlydegraded— the partial-failure envelope is honest, but four of six domains can never appear in the home/continue/favorites feed. The "blended" home is structurally Tara+Arete-only. Fix sketch: Repeat the C1 facade pattern for veritas + nyx (both have real repositories), bridge nisaba's adapter to the in-BFF nisaba store it already mirrors (B6/E2 did this for daily-passage on another path —getDailyPassageshould read the same store), and metis to its existing/api/*service; contract round-trip tests per C1.
P1#
16. Home Arete practice section fabricates streaks/progress on fallback, labeled only "Curated practice thread"#
Severity: P1 Evidence:
apps/oshun/web/src/components/home/homeAretePracticeModels.ts:131-217 —
FALLBACK_HOME_PRACTICE: goals with streakDays: 12/9/17,
progress: 68/54/73, continuation "Morning commitment loop — 58%",
userId: 'demo-user'; used whenever input.practice == null (loading or error)
via :217. Disclosure pill at HomeAretePracticeSection.tsx:267-271 reads
"Curated practice thread" — which does not say the streak numbers aren't yours.
Spec promise: features.md:325-326 (Arete weekly review home module); the
C2/C3 work made Arete streaks real precisely so numbers like these would be
honest. What the code does: on any /v1/arete/practice/home failure (and
during load on slow links) the member sees specific fabricated streak/progress
numbers beside the real streak elsewhere. Contrast the Veritas module in the
same directory (homeVeritasBriefingModels.ts:110-126), which was rewritten to
an explicit no-fabrication notice — the pattern exists; Arete (and Nyx, below)
weren't given it. Fix sketch: Mirror the Veritas fix: fallback carries stage
copy + "practice data unavailable" with zero numeric claims; delete the fixture
goals.
17. Home Nyx perspective fallback fabricates "Jupiter at opposition" tonight + a 42% observation continuation#
Severity: P1 Evidence:
apps/oshun/web/src/components/home/homeNyxPerspectiveModels.ts:95-140 —
FALLBACK_HOME_PERSPECTIVE: "Jupiter at opposition … reaches its closest point
to Earth this year", windowStart/peakTime frozen at 2026-03-27,
magnitude: -2.8, plus continuation "Track Jupiter through midnight — 42%,
lastOpenedAt …". Label on fallback: "Curated perspective"
(HomeNyxPerspectiveSection.tsx:238). Spec promise: features.md:325-326
(Nyx events home module); the B-phase ephemeris honesty work (real Meeus engine)
exists exactly so sky claims are true. What the code does: on outage,
asserts a specific astronomical event is happening tonight (it is dated ten
weeks ago) and that the member is mid-observation. Fabricated fact + fabricated
personal continuation. Fix sketch: Honest unavailable notice (no event
claim, no continuation); the real BFF route is ephemeris-backed, so the fallback
should claim nothing.
18. KNOWN RESIDUAL CONFIRMED — workspace→mobile handoff packet still fabricates the Iris continuity header (and more)#
Severity: P1 Evidence:
apps/oshun/web/src/components/workspace/irisMobileWorkspaceHandoff.ts:45-68 —
WORKSPACE_IRIS_CONTINUITY: static
coreBlockCount: 4, workingCount: 7, archivalCount: 18, episodicCount: 5, semanticCount: 11,
static userId: 'oshun-v1-workspace-user', consentState: 'granted'
(fabricated consent — C4 made consent real and default-ungranted),
lastUpdatedAt: '2026-05-06'. Additionally :141-163 fabricate a
voice_session (sessionId: voice-${tab.id}) and an assistant_transcript
(conversationId: assistant-${tab.id}) that don't exist. Spec promise:
features.md:339-341 (resumable assistant transcripts, hand-off between desktop
and mobile); features.md:269-270 (memory/consent state visible truthfully).
What the code does: the C16 transport is real (PUT to
/v1/iris/mobile-handoff), but the payload's memory counts, consent state, and
two of six items are fiction — mobile renders them as truth on resume. Fix
sketch: Fetch /v1/iris/adapter/continuity (and the real consent read) to
fill the header; include the voice/transcript items only when a real
session/conversation id exists; drop the static userId for the session user.
19. Mobile Explore search runs on a hardcoded in-file catalog, never /v1/search#
Severity: P1 Evidence:
apps/oshun/mobile/app/(tabs)/explore.tsx:217-585 — SEARCH_INDEX (in-file
items with fabricated freshness publishedAtMs: NOW_MS - 2h and
popularityScores); :586 TRENDING_QUERIES (fabricated "trending");
:1339-1340 all search/filtering runs over this constant. Zero network
calls in the 3,065-line file (grep client.|api.|fetch( = 0). Web explore
meanwhile uses live /v1/search
(components/explore/ExploreDashboard.tsx:1621), including the member's real
saved items/notebooks (C7). Spec promise: features.md:327-329 (universal
search across … notebooks, collections, courses …); features.md:367-369 (mobile
command surface for search and jump-to-anything). What the code does: mobile
members search a fabricated catalog that can never contain their notebooks/saved
items, with fabricated trending and recency — a second source of truth diverging
from web search. Fix sketch: Point the explore search box at
GET /v1/search through the existing typed BFF client (auth + domain filters
already supported); keep the curated collections rows as labeled editorial
content; derive "trending" from the analytics ingest (C11) or drop the label.
20. Assistant panel: silent fixture session history + a fake tool-action progress bar#
Severity: P1 Evidence:
apps/oshun/web/src/components/assistant/AssistantPanel.tsx:1884-1887—loadSessionHistorycatch →setSessionHistory(SIMULATED_SESSION_HISTORY);:651-664four fabricated sessions with topics ("Evening meditation routine", "Weekly goal review").:1545-1578— when the message mentions "session"/"check-in", the panel renders "Starting … session..." / "Running daily check-in..." with a random-incrementsetIntervalprogress bar that always reachesstatus: 'complete'— no action is performed; the message is simply sent afterwards. Spec promise: features.md:320-323 (assistant dock with persistent context handoff); features.md:339-341 (resumable assistant transcripts). What the code does: outage shows fabricated past conversations as the member's; the progress theater claims an action ran and completed when nothing did (C9/C14 made real runs and replies possible — this UI predates them). Fix sketch: History failure → honest "history unavailable"; delete the keyword-triggered fake tool action (real suggested-actions already navigate/queue real work).
21. E6 cross-device workspace sync is write-only: nothing ever reads the durable slot back#
Severity: P1 Evidence:
apps/oshun/web/src/components/workspace/MultiPanelWorkspace.tsx:463 —
pushClientState('workspace-layout', …) on every tab change. Repo-wide grep:
pullClientState and mergeByUpdatedAt (lib/client-state-sync.ts:33,50+)
have zero callers. Tab restore still reads only localStorage
(MultiPanelWorkspace.tsx:392). The other three allow-listed slots
(onboarding-progress, recent-searches, study-plan-drafts) have neither push nor
pull (recent searches remain pure localStorage —
UniversalSearchPanel.tsx:103-114). Spec promise: features.md:337-338
(multi-tab support with per-tab continuity, stable deep-link state);
features.md:411-412 (cross-device continuity). What the code does: "another
device resumes the same tabs" (the E6 claim) cannot happen — the server copy is
written and never read. Stored state never consulted on the hot path. Fix
sketch: On workspace mount (signed-in), pullClientState('workspace-layout')
→ mergeByUpdatedAt with the local tabs before first render of restored tabs;
adopt the same 6-line pattern for recent-searches in UniversalSearchPanel.
22. "Report failed charge" injects a fabricated payment failure into the member's own billing state#
Severity: P1 (subsumed by finding 3's rebuild, listed separately because the
control is actively harmful) Evidence:
apps/oshun/web/src/components/profile/BillingSection.tsx:280-291 —
simulateBillingFailure() →
recordPaymentFailure({ reason: 'Card was declined by issuer.' }) → notice
"Payment issue detected. Complete recovery actions to keep access active.";
wired to the customer-facing "Report failed charge" button (:651). Spec
promise: features.md:401-402 (billing entry); features.md:428-429 (honest
states). What the code does: a customer trying to report a real billing
problem instead creates a fake declined-card state and is told their access is
at risk. The "Retry payment now" recovery then "completes" against the same
fiction. Fix sketch: Route the button to the real feedback/support intake
(B14's POST /v1/feedback exists) with a billing category; delete
simulateBillingFailure.
P2#
23. "What's New" feed is a stale hand-coded changelog that contradicts the product#
Severity: P2 Evidence:
apps/oshun/web/src/components/WhatsNewDropdown.tsx:32-86 — CHANGELOG frozen
at v0.8–0.9 / Feb 2026, entries like "Dark theme polish" (the shipped shell is
the cream Lilith system per E7). No fetch (grep: 0 network calls). Spec
promise: features.md:416-417 (in-app changelog, "what's new" feed). What the
code does: serves four-month-old, partially false product education; meanwhile
C8 built a real authored-communications store with localization that could carry
this feed. Fix sketch: Serve entries from the C8 communications store (new
changelog audience/kind) or at minimum refresh the static list and remove
false entries.
24. Account switcher computes "last active" against a frozen clock#
Severity: P2 Evidence:
apps/oshun/web/src/components/ShellLayout.tsx:225 —
ACCOUNT_SWITCHER_NOW_MS = Date.parse('2026-05-07T12:00:00.000Z'); fed to
buildConsumerShellAccountSwitcher at :814. E8 made the identities real but
left the frozen now, so relative recency labels/ordering are computed against
May 7 forever. Spec promise: features.md:413-414 (multi-account switcher
with explicit identity indicator). Fix sketch: Use Date.now() captured
client-side post-mount (the file already uses that pattern for
shellMountedAtMsRef).
25. Orphaned fixture dashboards still exported beside the live home: KpiGrid (hardcoded sessions = 28, seeded fake sparklines) and CrossDomainHub#
Severity: P2 (orphans — no live consumer found; flagged so they don't get
re-mounted) Evidence: apps/oshun/web/src/components/home/KpiGrid.tsx:523 —
const sessions = 28;; :104-112 generateSparkData invents 14-day trends;
only its skeleton is consumed (Skeleton.tsx:92,
ShellSurfaceStatePreview.tsx).
components/cross-domain/CrossDomainHub.tsx:108-125 renders
SIMULATED_RITUALS/SIMULATED_CROSS_RECOMMENDATIONS/SIMULATED_CORRELATIONS/SIMULATED_ACHIEVEMENTS;
zero consumers (repo grep). Spec promise: features.md:318-319 (the dashboard
reflects real model state). Fix sketch: Delete both (and SIMULATED_*
exports they anchor), or wire KpiGrid to the real profile/activity stats if it's
meant to return.
26. Mobile profile/preferences/privacy stores are memory-only — every setting resets on app restart#
Severity: P2 Evidence: apps/oshun/mobile/src/profile/store.ts:21 —
createMemoryKeyValueStorage() backs ALL mobile stores (profile, preferences,
privacy, data-rights, billing), unlike web's
createWebStorageAdapter(localStorage). Notification topics, personalization,
privacy toggles configured in the profile tab do not survive a relaunch (no
AsyncStorage adapter anywhere in the file). Spec promise:
features.md:401-405 (profile/settings incl. notifications, personalization
preferences); features.md:265-266 (continuity). Fix sketch: Provide an
AsyncStorage/SecureStore-backed KeyValueStorage adapter (the auth context
already uses secure storage for tokens — same seam).
UX / polish#
27. Voice-input amplitude bars are random noise, not mic levels#
Severity: UX Evidence:
apps/oshun/web/src/components/assistant/AssistantPanel.tsx:1811-1815 —
setInterval fills 12 bars with webRandomUnitInterval() while real
SpeechRecognition runs. Spec promise: features.md:320-321 (assistant dock
quality bar). Fix sketch: Drive bars from a AnalyserNode over
getUserMedia (or replace with an indeterminate "listening" pulse that doesn't
imply level metering).
28. Metis home fallback says "Resume course" for a course the member never started#
Severity: UX Evidence:
apps/oshun/web/src/components/home/homeMetisStudyContinuationModels.ts:47-55 —
FALLBACK_PRIMARY CTA "Resume course" → /courses/crs-002 with
progressLabel: 'Course path ready' when there is no continuation. Spec
promise: features.md:325-326 (Metis study continuation module). Fix
sketch: Cold-start copy should invite ("Start a course path"), not imply an
in-progress resume.
29. Adjacent-register inconsistency: home domain modules use three different degraded vocabularies#
Severity: UX Evidence: On the same home screen, a degraded Veritas
module says "briefing is unavailable … no graded claim is shown" (honest,
homeVeritasBriefingModels.ts:110-126); a degraded Arete module says "Curated
practice thread" over fabricated streaks (finding 16); a degraded Nyx module
says "Curated perspective" over a fabricated event (finding 17); the
recommendations lane says "Curated shell mix" (finding 7). "Curated" is doing
dishonest work in three of the four. Spec promise: features.md:428-429
(consistent loading/degraded states); features.md:260 (coherent product). Fix
sketch: One shared degraded-module presentation (the Veritas pattern) across
all six home modules; reserve "Curated" for genuinely editorial content that
makes no personal/factual claims.
DEPLOY#
30. Smart-app-banner store URLs point at listings that don't exist (and the Apple URL pattern is malformed)#
Severity: DEPLOY (store submission is a recorded deploy item) — with a small
P2 code edge Evidence: apps/oshun/web/src/lib/mobile-store-links.ts:1-3 —
https://apps.apple.com/app/oshun (App Store URLs require
/app/<name>/id<digits>; this 404s structurally, not just pre-submission) and
the Play URL for an unsubmitted package; SmartAppBanner.tsx:151,161 sends
users there. Spec promise: features.md:443-445 (store submission assets,
listing content); features.md:430+ (public-web-to-app conversion funnel). Fix
sketch: Env-gate the banner (OSHUN_APP_STORE_URL/OSHUN_PLAY_STORE_URL
unset → suppress the store CTA, keep the PWA install path), fixing the malformed
Apple pattern when the real id exists.
Severity count#
| Severity | Count |
|---|---|
| P0-SEC | 0 |
| P0-HONESTY | 13 |
| P0-STRUCT | 2 |
| P1 | 7 |
| P2 | 4 |
| UX | 3 |
| DEPLOY | 1 |
| Total | 30 |
Notes for the fixer: findings 3+4 (auth-client seeds) and 16+17+29 (home fallback register) each share one root fix. Finding 14 is a one-file fix with outsized honesty coverage (54 routes). Finding 15 is the largest build item (two facades + two bridges) and is the C1 follow-up the audit already named.