Source of truth: V1/features.md (6,241 lines), V1/ARCHITECTURE.md,
V1/DEPENDENCIES.md, V1/TODOS.md — audited fresh against the codebase by 13
parallel read-only agents (one per major spec area), each instructed to treat
ONLY code as evidence and to search adversarially for stubs, fixtures, and
unwired machinery. This document is a new primary-source baseline ordered by
what blocks the V1 launch promise. The per-slice verdict counts below total ~128
OK, ~204 PARTIAL, ~63 STUB, ~40 MISSING, ~37 DEPLOY across ~470 audited spec
promises.
Status discipline: every task below starts [ ]. A task is marked [x]
only after the code for it has been written/verified in a session, with the real
commit hash recorded. No exceptions.
How to read this#
- P0-SEC — exploitable security gap. Fix immediately.
- P0-HONESTY — result-faking stub (fabricates data/success it didn't compute) on a live surface. The repo's own bright-line rule.
- P0-STRUCT — structural gap that makes a whole spec pillar unreachable.
- P1 — important wiring/realness gap; the machinery usually exists.
- P2 — polish, durability, or coverage gap.
- DEPLOY — code-complete fail-closed; needs external creds/infra. Not a code task.
The six systemic patterns (root causes)#
Nearly every finding is an instance of one of these:
-
The
/v1/oshun/*facade does not exist. The BFF's six domain adapters (apps/oshun/bff/src/adapters/domain-service-adapters.ts) dial downstream services at/v1/oshun/*paths. No server in the repo implements that contract —apps/tara/apiserves/api/v1/*,apps/arete/apiserves/v1/<resource>,apps/veritas/api+apps/nyx/apiserve/api/v1/*, Metis serves/api/*, and Nisaba has no service at all. Every adapter-backed route 502s by construction, even in dev with everything running. The contract test mocks fetch, so it can never catch this. -
The fixture cliff. Consumer hub rooms (
/tara,/veritas,/nyx,/nisaba…) fetch the BFF with honest unavailable states — but one click deeper, the presentational depth pages (src/lib/lilith-data/*-depth.ts: nisaba-depth 17 fixture refs/0 BFF calls, veritas-depth 17/0, metis-depth 11/0, arete-depth all-fixture) and the entire/domains/*power-user layer (18+ components on*-simulation-data.ts) render fabricated user data, fabricated journalism, and fabricated scholarship with identical visual authority. A user cannot tell which register they're in. -
Orphaned real engines. The best code in the repo has zero runtime consumers: Arete streak-recovery (grace/freeze/repair), Veritas source-quality geometric composite + editorial state machine + attestation lifecycle, Nisaba collation/philology/languages (1,700-line Needleman-Wunsch), Metis IRT 3PL + mastery bands + gradebook emission + BYOM safety harness, Iris memory store (immutable revisions) + recall pipeline, Lilith 13-rule crisis catalog + tone bands, agentic-studio (11.3k lines, 242 tests) grants/handoff/replay/budgets,
@oshun/search-discovery,@oshun/billing-support,@oshun/studio-authoring(~30 modules, 1 consumed),@oshun/customer-curation(smart collections, version awareness),libs/shared/audit-platform(89 modules),libs/shared/queue. The systematic failure mode is the last mile: tested libraries pointed at nothing. -
Result-faking stubs on live paths. ~20 bright-line violations (full list in Phase B below) — fabricated downloads, fabricated DSAR exports, fabricated provisioning, fabricated provenance claims, fabricated "grounded" answers, fabricated user statistics.
-
Management without enforcement. API keys are stored but never validated on any request; webhooks are authored but never dispatched by real events; role templates never feed the live authz check; authored banners/templates/ help articles never reach customers; armed kill-switches never reach the execution route (it reads them from the request body); Lilith policy is bypassed by a 5-keyword matcher; consent/quiet-hours flags exist in the dispatcher but the BFF feeds defaults.
-
Observability façade. Production analytics sink silently discards every event (
taraAnalytics.ts:387); 68/69 web telemetry modules never transmit; the BFF's Prometheus module is never registered; no OpenTelemetry anywhere; dashboard manifests have zero consumers.
Work backlog#
Tasks are ordered for execution. One task, one verification, one mark.
Phase A — Security (do first)#
- A1. Auth-gate
POST /v1/admin/privacy/dsar/erase— (DONE 2026-06-10, commitcd291ccae7.)createAuthPreHandler+admin:*/admin:workspace:privacyscope check; 5 auth unit tests (401/403-customer/403-wrong-workspace/privacy-scope-admits/admin-star) + the live-Postgres erase round-trip re-verified with auth headers. Along the way: repaired the staleDurationBuckettest fixture, added the missing Prisma migration for schema↔DB drift (3 duration-bucket columns +lilith_tone_review;goal3_stub_*untouched), and added the missing@oshun/contracts/*subpath aliases to the vitest base config (prefix-matching was mangling them). - A2. Auth-gate
POST /v1/admin/safety/crisis-frame/activate— (DONE 2026-06-10, commitcd291ccae7.) Route extracted toregisterCrisisFrameActivateRoute(unit-testable without Redis), gated onadmin:*/admin:workspace:moderation; 5 auth unit tests assert nothing publishes on 401/403; full live Redis+Postgres cascade integration test re-verified with auth. - A3. Auth-gate the reminder routes — (DONE 2026-06-10, commit
6eea8056d6.) schedule/run-cycle now requireadmin:workspace:messaging(oradmin:*); inbox requires a session and serves the token's own user — explicit recipientId only for self or operators (403recipient_mismatchotherwise). 11 route tests green incl. 401-sweep, 403-customer, cross-user-inbox-denied; the in-process worker uses the store directly and is unaffected. No UI callers existed. - A4. Telegram
botToken()fail-open default — (DONE 2026-06-10, commit6eea8056d6.) Production with noOSHUN_TELEGRAM_BOT_TOKENnow 503stelegram_not_configuredon verify-initdata + login-widget instead of verifying against the public dev constant; dev fallback preserved.requireWebhookSecretwas checked and is already fail-closed (the audit's claim there was wrong). 2 new tests (prod-503, dev-fallback-401). - A5. Server-side kill-switches/budgets on
/v1/agentic/runs/execute— (DONE 2026-06-10, commit8728a63794.) Bearer auth now required (the route was fully anonymous — real tools ran for any caller); actor = authenticated principal, token tenant claim overrides the body. Operator-armed switches resolve server-side per request from the SAME durable-backed store the admin arm/disarm route mutates (agent_family/tenant/global→family/tenant/globalscopes viatoExecutionKillSwitch); client switches/budgets only add constraints (budgets are tighten-only by construction — no server budget registry exists yet; that's C9-adjacent). 11 unit tests + e2e auth/401 legs. - A6. Entitlement tier from spoofable header — (DONE 2026-06-10, commit
9251c638e8.) Tier resolves from the session's persisted plan (plan values ARE the tiers); header honored only outside production for sessionless requests; elevating domain-tier overrides likewise dev-only; restrict-only suspensions unchanged. AddedcustomerAuthStateStore.updatePlan(the C10 settlement hook). 5 new tests; 158 existing entitlement tests pass unchanged. - A7. User-scope the library collections route — (DONE 2026-06-10,
commit
478a2413ff.) Session required (401 anonymous);ownerUserIdthreaded through both store legs (additiveowner_user_idcolumn, legacy NULL rows visible during migration, canonical dual-write carries the real owner); reads filter to the caller; fixture catalog dev-only; web create form sends the bearer token. Owner-isolation tests. Also repaired two stale prod-503 test expectations for/v1/payments/{methods,invoices}(those routes became real earlier; tests now assert the honest production behavior) and committed the regenerated prisma client for the A1 migration. Phase A complete. - A8. Telegram rate limiter constructed per-update — (DONE 2026-06-10,
commit
6eea8056d6.) Both legs (BFF webhook + grammY app) hoisted to a process-scoped limiter with a test reset hook; regression tests assert the 13th update in a 60s window gets the rate-limit reply on each leg. - A9. Crisis suppression server-side on the Telegram payment path —
(DONE 2026-06-10, commit
f1d123cbdf.)bindCrisisFrameStoreat the composition root (binds whenever Postgres exists) +isCrisisFrameActiveForUserover all five surface markers. Telegram invoice ORs the server verdict with the client flag (body can no longer clear a frame); crypto quote 403scrisis_suppressedfor a framed session user BEFORE the availability check (session-optional bearer resolution). 5 tests incl. body-says-false-still-suppressed.
Phase B — Result-faking stubs → honest-or-real#
Each of these returns a result it never computed. Fix = make it real where the backing store exists in-repo, else fail loud/honest.
- B1. DSAR self-serve export fabricates completion (P0-HONESTY) — (DONE
2026-06-10, commit
2fb19d1ec7.) Newbundle-builder.tsassembles a REAL bundle from 9 in-BFF stores (profile, consents, saved items, collections, notebooks, conversation history, personalization vector, reminder inbox, active persona); honestavailable:falsefor scopes with no in-repo store. New durablebundle-store.tsholds the bytes; the create route completes with a manifest hashed over the REAL bytes + a real served download URL (absolute againstOSHUN_PUBLIC_BFF_URL— the contract requires a URL), failing honestly on assembly error. New owner-scopedGET …/:exportId/bundle(403/404/401). 13 tests incl. an A-to-Z seed→export→download withsha256(bytes) == manifest. 57 privacy/export integration tests still green. - B2.
/v1/metis/ingestfabricates a queued job (P0-HONESTY) — (DONE 2026-06-10, commit6c759f9994.) Newmetis/ingest-pipeline.tsderives a real deterministic study outline (segments + reading-time + key terms + study prompts) from provided text; new durablemetis/ingest-job-store.tspersists auth-scoped jobs (text → completed with a real outline; url/pdf → honestawaiting_source_contentwith no fabricated outline; bad input → 422). New owner-scopedGET /v1/metis/ingest/:jobId; web form sends the bearer + renders the real outline. 12 tests + 68-test route suite green. - B3. Tenant onboarding fabricates provisioning (P0-HONESTY) — (DONE
2026-06-10, commit
6a2f074082.) New durabletenant-console/tenant-onboarding-store.tsvalidates against the tenant-consolevalidateTenantcontract (kind/residency/hierarchy vs a real parent/seats), persists aprovisioningrecord then completes it toactivewith seat allocation + isolation boundary; operator-scoped POST, 422 with field-level issues on violation.GET /v1/tenantslists real tenants first (fixtures dev-only, now session-gated); new operatorGET /v1/tenants/:tenantId. 9 tests. - B4. Living Scenes fabricated provenance claims (P0-HONESTY) — (DONE
2026-06-10, commit
b2d53825ae.)newMaterializationnow returns a PENDING record (no baked-in watermark, null cacheLocation);completeMaterialization(record, evidence)is the only path tomaterialized:true. The Lilith pre-share check surfaces a non-blockingmaterialization-pendingnote instead of claiming/blocking;audioWatermarkIntactis tri-state and reports'not-applicable'for the silent render. BFF share route drops the fabricatedoshun://cache location. 38 lib + 18 BFF route tests green; D4 wires real materialization behind the honest seam. - B5. Telegram fixture Sophia grounder on the live webhook (P1) — (DONE
2026-06-10, commit
33258b7a8e.) Newtelegram/sophia-grounder-bridge.tsadapts the BFF's real Sophia seam (nisabasearchLibrary→ extractive composer → optional LLM synth) into theSophiaRetrievercontract;app.tswires it intoregisterTelegramRoutesso the live webhook grounds in real sources (the fixture grounder is gone from the live path). The bot abstains gracefully (groundOrAbstain+TELEGRAM_ABSTENTION_COPY) across text/voice/inline when there are no sources. 9 tests; messaging-channels suite (223) green. - B6. Sophia read-adapters fabricate source records (P1) — (DONE
2026-06-10, commit
3bf5cfa293.)getSourceresolves through the real nisabasearchLibrary(real metadata + kind-derived reliability; honest minimal record on no hit — noSophia Corpusauthor, noevidence.oshun.localURL, no id-length reliability);getSourceGraphbuilds nodes/edges from real retrieval hits (empty graph otherwise);listNotebookstakes an injected real reader wired tonisabaConsumerStateStore(honest[]without it). 4 adapter + 10 route tests green. - B7. AssistantPanel fabricates an assistant reply on outage (P1) —
(DONE 2026-06-10, commit
895ddd688b.)apps/oshun/web/src/components/assistant-dock/AssistantPanel.tsx:1931-1940+generateSimulatedResponse:912inject a simulated turn with hardcodedconfidence: 0.85when the BFF errors. Replace with the honest error state (the 403 path already has one); delete the simulated-response generator. - B8. Arete AI coach fabricates user statistics (P0-HONESTY) — (DONE
2026-06-10, commit
5ecbc603fb.)apps/oshun/web/src/lib/arete/coach-responses.ts:50,63,89templates embed fake streaks/percentages as if read from the user's data. Ground in the real habit store (/v1/arete/habitsexists, same process) or strip every invented number. - B9. Tara analytics dashboard invents a practice history (P0-HONESTY) —
(DONE 2026-06-10, commit
92f54babd6.) Newtara/analytics.ts+ authGET /v1/tara/analyticscompute the dashboard from realgoal3_stub_tara_completionrows (listForUser); component fetches it, honest 'No practice yet' empty state; seeded generators deleted. 5 tests. ORIGINAL:apps/oshun/web/src/components/domains/tara/TaraAnalyticsDashboard.tsx:83-106generates the user's history withseededRandom(42). The real completions table (goal3_stub_tara_completion) can power a real version; add an honest empty state for new users. - B10. Nyx
Math.random()forecasts (P1) — (DONE 2026-06-10, commit41e9b4ac71.) The twoMath.random()jitters in the sky-conditions forecasts are now deterministic illustrative values;NyxSkyConditionsrenders an explicit honest disclosure that the live weather/seeing/transparency feed is NOT connected (sun/moon timings stay real). Full live-feed wiring is deploy-bound. 2 tests. ORIG10:apps/oshun/web/src/lib/nyx/nyx-widgets-simulation.ts(e.g.:2238) — random numbers presented as weather/seeing forecasts, with comments mislabeling them "legitimate jitter". Compute what the in-repo ephemeris genuinely supports (twilight, moon interference, Bortle descriptors); render honest "live forecast not connected" for weather-dependent fields; delete the random generators. - B11. Mobile download manager fabricates downloads (P0-HONESTY) —
(DONE 2026-06-10, commit
b60952a467.) NewFileTransferPortseam (expo-file-system + expo-crypto default, injectable double);executeDownloadperforms a real transfer + SHA-256 verify (mismatch→corrupt, error→failed);verifyChecksum/attemptRepairare real. 4 Jest tests. ORIG11:apps/oshun/mobile/src/data/download-manager.ts:425-463:executeDownloadmarks complete without fetching; checksum verify + repair always succeed. Implement withexpo-file-systemdownloads + real SHA-256 (expo-crypto), honest failure states. The queue/eviction scaffolding around it is real and reusable. - B12. Telegram bot fake effect claims (P1) — (DONE 2026-06-10, commit
fbe839e865.) Added aTelegramEffectsPortseam to the messaging-channels bot (telegram/effects.ts);/save,/quiet,/stop,/voice, thesave:/quiet:callbacks, and inlinesave <…>now route through it and reply from the ACTUAL outcome — honest "not connected" when no port is wired, never a fabricated success. Deleted the misleadingsaveInlineToNotebookid-faker. BFF adapter (telegram/effects-adapter.ts) maps the verified Telegram id →iris:<id>and writes real stores: a new durable per-userTelegramUserStateStore(captures + voice toggle +/stopsuppression flag) for save/voice/stop, and the shared notification-preference store for/quiet(so it actually gates delivery). New self-scopedGET /telegram/capturesread route. Durable snapshot wired inserver.ts. Tests: 4 new lib behaviors (honest-when-unwired, real save/quiet/stop/voice, bare-/saveinstructions) + 9 adapter/store + 4 route = real-write assertions throughout. ORIG12:/save,/quiet,/stop, inline "Saved to Oshun notebook" (libs/oshun/messaging-channels/src/telegram/bot.ts:138-161,inline.ts:62-74) claim writes that never happen. Add an effects port; wire the BFF to real stores (notebooks, notification prefs, link bindings); reply honestly when unlinked/unwired. - B13. Profile photo upload fakes success (P2) — (DONE 2026-06-11,
commit
f9dfd98146.) Wired a real upload end-to-end.POST /v1/profile/avatar(BFF) validates content-type (PNG/JPEG/WebP/GIF) + size (≤1.5 MB decoded, routebodyLimitraised) and stores bytes via the asset-store seam (resolveAssetObjectStore→ S3/MinIO, signed-URL re-signed on read) OR a durable inline base64 fallback (ProfileAvatarStore, snapshot-wired inserver.ts) → returns a self-containedavatarUrl(signed URL ordata:URL, no auth-on-<img>problem). Profile GET overlays the resolvedavatarUrl; added optionalavatarUrlto the sharedOshunUserProfile. Web: replaced the fake "Photo upload simulated…" notice with a real<input type=file>→uploadAvatarclient → renders the returned image, refreshes the profile, and shows an HONEST typed error (bad type / >1.5 MB / read / upload failure) — never a fabricated success. Tests: 8 upload-module + 5 route (incl. 401/400/413/no-leak/round-trip) + 6 web client + 3 web component (real upload renders image, failure shows honest error, button opens picker). ORIG13:apps/oshun/web/src/components/profile/ProfileSettingsPanel.tsx:313"Photo upload simulated…". Wire a real upload (asset-store seam with a durable fallback) or remove the control. - B14. Feedback capture dead-ends in localStorage (P1) — (DONE
2026-06-11, commit
d0fe8845e4.) A ready report now actually transmits. New BFFFeedbackIntakeStore(durable, snapshot-wired inserver.ts) + routes:POST /v1/feedback(validates, stamps the AUTHED submitter — a client-claimeduserIdis never trusted),GET /v1/feedback(the member's own reports),GET /v1/admin/feedback(operator triage queue, admin-scoped) +POST /v1/admin/feedback/:id/triage(acknowledge/resolve). WebsubmitFeedbackclient posts the real submission payload;ShellFeedbackCaptureHub.captureRequesttransmits on a ready capture and the notice reflects the ACTUAL outcome — "sent to the team" only on success, "saved on this device — couldn't reach the server" on failure, "saved but not sent — blocked" for an incomplete report (localStorage kept as offline cache). Tests: 4 store + 7 route (401/400/leak/scope-403/triage/404) + 3 web client + 3 component (real transmit, honest failure, blocked-never-transmitted). ORIG14:apps/oshun/web/src/components/shell/ShellFeedbackCaptureHub.tsx:303builds a correct report (trace IDs, route) then never transmits. Add a BFF intake route + durable store + operator triage read. - B15. Fabricated Sophia lineage citations on Tara teachers (P1) —
(DONE 2026-06-10, commit
5b3d1c6121.) Stripped the hand-authoredlineage(thesophia.oshun.examplecitation trail + "Sophia verified …" summary +verifiedAt) fromtara-teacher-001;TaraTeacher.lineagenow documents it may only be populated from a real Sophia verification read;TaraTeacherProfilerenders an honestTeacherLineageUnverified"not yet verified" state in its place. NewTaraTeacherProfile.test.tsx(3 tests) asserts the unverified state renders, no citation anchors exist for any teacher, and the source data ships nosophia.oshun.example/citationTrail/verifiedAt/lineage. ORIG15:apps/oshun/web/src/lib/tara/tara-simulation-data.ts:141invents verification trails + reviewer names onsophia.oshun.exampleURLs. Fake trust signals are worse than none: strip them; render an honest "not yet verified" state.
Phase C — Structural wiring (highest leverage, in order)#
- C1. Implement the
/v1/oshun/*facade for Tara + Arete — (DONE 2026-06-11, commits5869e40db2(arete) +43bf916f9c(tara); user chose the downstream-bridge-router architecture.) Arete: 24-endpoint facade (apps/arete/api/src/routes/oshun-facade.ts) over the SAME repositories the native routes use — goals (canonical status/horizon mapping, hierarchy→milestones), habits (reusing the nativeapplyStreakUpdatestreak math), journal, balance (trend vs previous assessment), member-level streak stats from real completions, continue plan/check-in, insights + accountability reminders DERIVED from real records (at-risk streaks, stalled goals, journaling gaps), saved/reminder/dismissal state in a redis-write-through facade store; plus/v1/arete/healthz. Tara: facade (apps/tara/api/src/oshun-facade/) over aTaraOshunStoreport — Drizzle impl queries the same Postgres tables the native routes use (Oshun ids resolved to shadowusersrows via deterministic bridge email), endpoints for recommended (featured/playCount ranking), continue, course progress, favorites CRUD, session audio (real catalog encode + member resume position; size = documented 128 kbps estimate), streaks, history; probe = existing/ready. Both fail-closed: production refuses without{ARETE,TARA}_OSHUN_FACADE_TOKENmatchingx-oshun-service-token(BFF sends it fromOSHUN_DOMAIN_SERVICE_TOKEN). Contract round-trip tests (11 arete + 9 tara) boot the REAL routers in-process and drive them through the REALcreateDomainServiceAdapters— caught + fixed real drift on day one (getActiveGoalsdroppeduserId). Veritas/nyx repeat = follow-up of the same pattern. ORIGC1: bridge routers inapps/tara/api+apps/arete/apiexposing the adapter contract over their real stores (or rewire the adapters); then the BFF's fail-closed routes (recommended/continue/favorites/streak/history, practice/home) light up with real data. Add a contract round-trip test that boots the real router (the current test mocks fetch and can't catch path drift). This single task converts dozens of DEPLOY-verdict routes to OK; repeat for veritas/nyx after. - C2. Arete check-in mutation + humane streak policy at runtime — (DONE
2026-06-11, commit
b7aa23407e.)POST /v1/arete/habits/:id/check-inrecords the V1-contract statuses (done/partial/skip/decline/miss) durably: newgoal3_stub_habit_checkintable (one row per habit/user/day, same-day amendable) + canonicalv1_arete_check_indual-write, per-member.GET /v1/arete/streaknow COMPUTES from the member's real check-ins through the previously-orphanedevaluateAreteHabitRecoveryengine (humane fold rules: engaged advances, skip/decline rest FOLDS IN, unexplained absence breaks; recoveryNote/stage/disposition from the real plan; 28-day heatmap from real records; honest zeros; 503 fail-closed without Postgres). Fixture habits KILLED from/v1/arete/habits— stored rows only, with per-member todayKept/streakDays recomputed from that member's check-ins. Bonus root-cause fix:tryConnectPostgrespassedconnectionStringto a client that takes discrete fields — the ENTIRE goal3 Postgres tier silently fell back to file storage; parsed properly now, reviving all 24 live-DB integration tests. Tests: 10 pure fold-rule + engine cases (exact values), 3 route 422/503 legs, 2 new live-DB legs (record→amend→scoped reads + canonical dual-write; findById/updateStreak). ORIGC2: addPOST /v1/arete/habits/:id/check-in(done/partial/skip/decline/miss per the contracts) writing durably, then compute/v1/arete/streakfrom real check-ins via the orphanedevaluateAreteHabitRecovery. Kill the fabricated fixture habits merged into every/v1/arete/habitsresponse (domain-stubs.ts:1060-1076). The spec's core loop has no execution path today. - C3. Swap
domain-stubs.tsfixture reads to real reads — (DONE 2026-06-11, commit00dae3c616.) Per-user reads converted to real/honest: tara/today (real streak or 0; the fabricatedmood: 'curious'field deleted — no real source, no web consumer read it), tara/sittings (curated catalog + per-member state from real completions; never pre-marked 'done'), tara/ritual (curated definition + real continuation,lastObservedAtIso: null/0 honest baseline), arete/streak+review (streak = C2; review highlights now computed from the member's real check-ins, fabricated "Five mornings" rows gone, curated prompts kept), metis/courses (stored proposals only — fixture merge killed), devices (auth-required read of the REAL durable device-token store; fabricated "This browser" row gone;activeSurfacePath: nullover a fabricated '/'), memory (already guarded), assistant/context (verified already honest-empty — carrySize 0). Production-guarded every remaining fabricated-data fixture viaguardedFixtureRoute: veritas/drift (the audit's named hazard), arete/offerings, metis/lessons, agents, orchestrator, profile/notifications, persona/voice, user-reports, atelier/jobs. Deliberate non-guards documented in place: /v1/health (real), /v1/library/items (curated content), assistant/context (honest empty). Tests: 84/84 route tests green incl. 9 new prod-503 legs + 5 new real-conversion cases (sittings never pre-done, ritual honest continuation, review empty highlights, courses no merge, devices 401/empty/registered round-trip). ORIGC3: the file's own header documents the intended swap toapp.domainAdapters. Convert per-user reads (tara/today, arete/{streak,review}, metis/{lessons, courses}, memory, devices, assistant/context, persona/voice) to adapter/store-backed reads with honest empty states; production-guard every remaining fixture (/v1/veritas/driftships fabricated evidence in prod today via unguardedjsonRoute). - C4. Wire Iris memory for real — (DONE 2026-06-11, commits
698013fd8b(part 1) +94585570b9(part 2).) Part 1: killed the fixture seed — a new member starts honestly EMPTY (zero memories, documented adaptive defaults, consent UNGRANTED — the old adapter pre-granted all three consents and seeded identical Nisaba-study memories for every user); live clock (frozenDEFAULT_NOW2026-03-22 deleted;options.nowstays as a test override); new settings-rolePOST /v1/iris/adapter/consentsrecords the member's REAL consent decision — the only path to durable memory, which the canonical engine correctly suppresses until granted. Part 2: durable snapshot persistence (wireDurableIrisMemoryin server.ts — explicit Date/Set serialization, write-through on every mutation incl. consent; a member's remembered context + consents survive a deploy); assistant engine now constructed WITH theIrisMemoryBridgeover the same consent-gated store (canonical approved Oshun-Navigator customer identity viabuildIrisAssistantIdentity); web/profile/memorycontrols now key on the REAL session user, start honestly empty (pending consents, no fabricated "Renata" record), and hydrate from/v1/iris/adapter/review+/consents(coarse→category consent mapping documented as a faithful projection; localStorage demoted to cache). Tests: 12 iris adapter/route (honest-empty, consent-flip, consent-gated durable writes, forget/export over real records) + 10 memory-controls component tests rearranged to seed realistic state at the storage boundary instead of relying on a global fabricated seed. ORIGC4: replace the fixture-seeded frozen-clock adapter (iris-memory-adapters.ts:48,295— identical seeded memories + pre-granted consents for every user) with the real@oshun/memory-irisstore on a live clock with durable persistence; construct the assistant engine WITH thememoryBridge(routes/assistant.ts:163omits it); point/profile/memorycontrols at/v1/iris/*instead of localStorage (hardcodedoshun-member-renata). - C5. Put Lilith policy in the line of fire — (DONE 2026-06-11, commit
16d176d5b0.)analyzeMessageSafetynow runsanalyzeLilithSafetyViaCrisisPolicy— the validated 13-rule crisis catalog + signal taxonomy with the real response-plan builder (required statements + real regional resources) — merged with the scope rules (medical/legal disclaimer, deception block) viamergeLilithSafetyAnalyses; the 5-keyword matcher is gone. The assistant message route runs EVERY member turn through it BEFORE processing: a crisis detection (or an operator-armed crisis frame viaisCrisisFrameActiveForUser→loadActiveCrisisFrame, giving the frame its consumer-surface caller) supersedes the contemplative reply with the policy's plain-language statements + resources in the normal response envelope; safety-bypass requests get a policy refusal. Crisis-frame suppression now covers payments (A9) + the assistant surface. Tests: 7 new (catalog detections the old matcher could never reach — panic, violence disclosure; canonicalsuicide-ideationtype + real resources; scope rules; route interception/refusal/ordinary-turn) + 8 existing lilith tests updated to the canonical taxonomy. ORIGC5: the BFF'sanalyzeSafetyhand-rolls a 5-keyword matcher (lilith-persona-policy-adapters.ts:596) instead ofdetectLilithCrises; the assistant engine imports no lilith module. Run assistant turns through the real crisis catalog + tone policy; giveloadActiveCrisisFramereal callers so an active frame actually suppresses surfaces (zero callers today). - C6. Generation outputs → gallery/lineage/provenance — (DONE
2026-06-11, commit
6de0a5fbc1.) Newgeneration/output-catalog.ts: at release time (Isis gatecompleteONLY — blocked/held outputs are never cataloged) the worker now writes all three: a realOutputRecordinto the SAMEoutputGalleryAdminStorethe/isis/output-galleryconsole reads (explicit request domain honored; kind-default routing domains documented; idempotent on retry), aderived-fromlineage edge in the real@isis/output-galleryOutputLineagetree, and a provenance record (job id, kind, model, generator, governance decision, SHA-256 request digest) served via a new operator-scopedGET /v1/generation/outputs/:outputId/provenance. Durable viawireDurableGenerationOutputCatalog. The gallery May-25 seeds are dev-gated — production starts EMPTY and fills with real released outputs;nowUnixSecondsis live. Tests: 4 new pipeline round-trips (release→gallery+lineage+provenance, blocked-never-cataloged, scope/404, retry-no-duplicate) + 188 existing generation/gallery tests green. ORIGC6: the job worker releases through an honest gate but writes no gallery record, lineage edge, or ProvenanceBundle; operator surfaces run on May-25 seeds. Write all three at job completion; surface real records in the consoles; dev-gate the seeds. - C7. Universal search over the user's real objects — (DONE 2026-06-11,
commit
8a9d4c1777.) Newsearch/user-object-candidates.ts:/v1/search's ranking pool now includes the member's REAL objects from the existing stores — saved library items (durable LWW store, each with its own domain), owner-scoped library collections, Nisaba notebooks, and Arete habits — alongside the curated seeds and live feed items. Domain-authorization + domain-filter respected; honest empty for a member with nothing saved. Test proves a real saved item + notebook rank in results and another member's search never sees them (11/11 search-route tests green). ORIGC7: replace/augmentUNIVERSAL_SEARCH_SEEDS(universal-search-seeds.ts:24) with real content: saved items, collections, notebooks, habits — all have BFF stores already. - C8. Close the authored→consumed loops — (DONE 2026-06-11, commit
6994d03659.) Newroutes/customer-communications.tsserving the SAME durable communications store the admin authoring routes mutate: (a)GET /v1/communications/banners— active, untargeted, localized authored banners (tenant/role-targeted ones never leak to the public shell); the webShellLayoutbanner stack now fetches and merges them (the old catalog stays a?statusBannerPreview=dev aid only, which it always effectively was — it rendered nothing by default). (b)GET /v1/communications/help— PUBLISHED customer-audience articles, locale-resolved + searchable;ShellHelpCenterHubfetches and merges them with the built-in editorial defaults. (c) reminder deliveries now render the operator's APPROVEDlifecyclenotification template (newest per channel,{{title}}/{{tenantLabel}}/{{startsAt}}variables) viabindReminderNotificationTemplates— the first consumer the templates store ever had. (d)GET /v1/status— the REAL status page derived from operator-maintained component states, open public incidents (latest update), and maintenance windows, withoverallStatusfrom the worst component. Tests: 4 new (banner targeting/localization, draft-never-served + publish flow, real component/incident status derivation, template render) + ShellLayout 57/57 + help hub green. ORIGC8: (a) customer banner stack reads a hardcoded catalog, not the authored store; (b) in-product help resolves from its own seeds, not authored articles; (c) notification templates are never rendered into deliveries; (d) status page is a labeled specimen — serve/v1/statusfrom the real incident/component stores. Four authoring stores, zero consumers. - C9. Operator dashboard ← real AgentRun lifecycle store — (DONE
2026-06-11, commit
8470b98131.) The execute route now PERSISTS the executed envelope (tool plan, evidence trail, cost ledger, final status) via newAgentRunLifecycleStore.recordExecutedRun— a fully-executed unterminated plan is finalizedcompletedwith a real completion timestamp; killed/throttled runs keep the engine's status. The admin agentic-operations snapshot now BRIDGES real lifecycle runs into the console inventory ahead of any seed rows (full contract mapping: status→bucket, cost→band, latency→band, severity, approval state, evidence/plan counts).defaultSeed()is dev-gated — production starts EMPTY and fills with real executed runs + operator mutations. Tests: new execute→persist round-trip (status completed, real completedAt) + 20/20 agentic + admin-ops suites green. ORIGC9: the admin agentic console rendersdefaultSeed()fixtures while real runs sit invisible inrun-lifecycle-store.ts; executed plans + their audit events aren't persisted at all (the execute route discards them). Persist run envelopes; bridge the two stores; dev-gate the seed. - C10. Crypto settlement → entitlement leg (in-repo half) — (DONE
2026-06-11, commit
7b2c9249f7.) NewPOST /v1/payments/crypto/settlements(payments/settlement-route.ts): HMAC-SHA256 signature-verified (timing-safe compare; 503 fail-closed withoutOSHUN_CRYPTO_SETTLEMENT_WEBHOOK_SECRET, 401 on bad signature), drives the REAL invoice state machine via the previously-uncalledconfirmCryptoInvoice(pending→confirmed; re-delivery acks idempotently; unknown invoices 404 — never fabricated). Invoices now carrypurchaserUserId+entitlementPlan: the quote route records the session-authenticated purchaser and the stated plan, and settlement flips the member's PERSISTED plan viacustomerAuthStateStore.updatePlan— the same field the A6 entitlement middleware serves. Anonymous invoices settle without a grant. Settled event logged with the grant outcome. Chain watcher remains deploy-bound. Tests: 5 (fail-closed, bad-signature, full quote-fields→settle→plan-flip→idempotent-redelivery, anonymous-no-grant, unknown-404) + 22/22 payments suite green. ORIGC10: nothing callsconfirmCryptoInvoice; no webhook receiver exists; no path flipsplanfree→pro on payment. Build the BFF-side signature-verified settlement receiver, drive the invoice state machine, publish the settled event, grant the entitlement (persisted plan upgrade — composes with A6). Chain watcher stays deploy-bound. - C11. Analytics: one real network sink + register the metrics module —
(DONE 2026-06-11, commit
779169a56a.) The library'sBufferedAnalyticsSinkalready WAS the HTTP sink (batching/retries/backoff posting{events}) — it just had no receiver and no caller. New BFF ingestPOST /v1/analytics/events(durable short-retention: 5000-event cap, 7-day prune-on-write) + operator readGET /v1/admin/analytics/events(observability-scoped, name/domain facets). New shared web transport (analytics/transport.ts) wires the buffered sink at the BFF ingest (+ dev console sink);taraAnalytics.tsflipped from its prod-discard sink to it.BffMetricsCollector(dead code) now registered: anonResponsehook records every request andGET /metricsserves live Prometheus text. Tests: 3 (batch ingest→operator read with facets + scope gate, 400 on bad body, /metrics real counters). ORIGC11: add an HTTP sink tolibs/oshun/analyticsposting to a new BFF ingest route with durable short-retention storage + operator read; fliptaraAnalytics.ts:387(prod discard) and the shared web client to use it; registerapps/oshun/bff/src/observability/metrics.ts(dead code today) so/metricsis live. - C12. Tenant-admin app → real BFF data — (DONE 2026-06-11, commit
8a960d0c03.) New BFF tenant-console reads (routes/tenant-console-reads.ts):GET /v1/tenant-console/{members,sso,audit}gated ontenant:admin:{tenantId}/tenant:admin:*scopes; members serves the real invite store (members + invitations + newseatPoolview), sso serves the tenant slice ofssoConnectionStoreas a config-only projection, audit is the NEW tenant-scoped read over the operator audit store (listAcrossOperatorsfiltered to events whosetargetIdorpayload.tenantIdreferences the tenant). BFF authz now accepts the tenant-admin app'stenant.-prefixed session tokens (same unsigned dev format + mandatorytidclaim, same env gate as dev tokens). Tenant-admin app: new server-sidetenantBffGethelper forwards the session cookie as bearer; members/audit pages fully rewritten over the live reads (honest backend-unreachable + empty states, invitations table, seat counts); identity page now renders the tenant's REAL SSO connections with its policy-engine checks explicitly labeled "sample inputs"; the nine remaining engine-demo pages (agents/content/roles/status/integrations/ notifications/policy/data/help) are labeled as demo data. 4 new BFF route tests (tenant scoping, cross-tenant 403, operator-without-tenant-scope 403, blanket scope, SSO projection, audit tenant filter); tenant-admin suite + both typechecks green. ORIGC12: the strictly-isolated shell is real but zero pages fetch; real tenant-scoped backends already exist for invites/seats, SSO connections, SCIM users, OneRoster. Wire those pages through tenant-session-bound proxies; add a tenant-scoped audit read (the operator store has no tenant filter); label any remaining fixture pages as demo data. - C13. Admin-mobile: mount the review action sheet — (DONE 2026-06-11,
commit
ede6eec706.) NewadminMobileReviewQueueClientfetches the live review queue fromGET /v1/admin/workspaces/review(the same per-operator snapshot the admin web cockpit renders) and decodes records through the existingdecodeAdminMobileReviewItem(derived severity + SLA status, queue-position sort, malformed-record drop count). NewAdminMobileReviewQueuePanelrenders the queue asAdminMobileReviewCards and mountsAdminMobileReviewActionSheetinline under the tapped card — approve/reject/request-changes now performable from the shipped/workspace/reviewscreen; a finalized decision collapses the sheet and refreshes the queue; the sheet's step-up demand routes through the real/step-upscreen. Honest loading/error/empty states with retry. Also fixed the staledist/libs/oshun/navigationbuild that broke the app's typecheck (missingegbeworkspace). 2 new client tests (decode/sort/ severity/SLA + 401/403/malformed/network failure mapping); all 290 admin-mobile tests + typecheck green. ORIGC13: decision/ escalate/assign HTTP clients +AdminMobileReviewActionSheetexist but no screen mounts the sheet; approve/reject can't be performed from the shipped screens. Highest-leverage finish in the admin slice. - C14. Assistant LLM seam (env-gated, fail-closed) — (DONE 2026-06-11,
commit
6b4c93b6f5.) Newassistant/llm-reply-composer.ts: the SAME triple-keyOSHUN_LLM_*gate as Sophia's synthesizer (null composer without all three creds), provider-agnostic chat-completions transport with 6s timeout. The message route now composes a free-text reply grounded ONLY in the deterministic turn — the engine's livegetSystemPrompt()(dead code made live: domain context, persona, daypart) frames the rewrite; the intent-router reply + its cards are the sole permitted facts; explicit never-invent + preserve-unavailability instructions. Every response is labeledresponseMode: 'retrieval'|'synthesized'; synthesized turns keepretrievalTextand null the stale template SSML. Composed output re-runs the REAL Lilith policy (C5) — flagged or thrown compositions fall back to the deterministic reply. Composer injectable viacreateApp(tests) à lasophiaAnswerSynthesizer. 7 tests: env gate, transport grounding-bundle/error/empty-content, retrieval label without creds, synthesized label + retrieval preservation, Lilith-flagged fallback, thrown-composer fallback; C5 suite re-green; typecheck green. ORIGC14: the shell assistant is a deterministic intent router;getSystemPrompt()is dead code. Wire the sameOSHUN_LLM_*seam Sophia's synthesizer uses: LLM composes free-text replies grounded in adapter data when creds exist, honest template fallback otherwise; label retrieval-vs-synthesis; run output through Lilith policy (C5). - C15. Multi-panel workspace + explore + activity off fixtures — (DONE
2026-06-11, commits
20e402a5ff+1616f07a24(part 1),ee789236e4+5ae52cbb89(part 2).) ACTIVITY: hook rewritten — live/v1/activitytimeline + real/v1/achievements/user⋈/definitionsachievements, honest EMPTY sections + per-sectionUnavailableSectionNotes for milestones/streak/digest (no backend projections exist), fixture fallback deleted, outage banner honest. EXPLORE: dead fixture layer (explore-simulation.ts+ unroutedCollectionDetailView) deleted; search was already live/v1/search;audit-simulation-data.test.tsrewritten to enforce the NEW posture. WORKSPACE:useWorkspaceLiveData.ts(continuity from/v1/activity, debounced live/v1/search, reading anchors from/v1/nisaba/notebooks, evidence from/v1/veritas/adapter/saved-articles?role=shell, each loading|live|unavailable); ALL six fixture blocks deleted fromMultiPanelWorkspace.tsx(CONTINUITY_ITEMS, SEARCH_RESULTS, READING_ANCHORS, EVIDENCE_SOURCES, INITIAL_NOTE, fabricated DEFAULT_WORKSPACE_TABS → two honest empty windows); STUDY_STEPS fabricated complete state removed; panels disclose loading/unavailable/empty and null-tolerate absent anchors; tab-state parsing no longer validates against fixture ids (live-resolution fallback instead); handoff + export-catalog builders take nullable reading/evidence with honest absence labels, fabricated progressPercent/turn counts/fixed notebook ids removed; export center defaults to the live passage item. Test suite (19) rewritten over a dependency-boundary mock of the live hooks; 142 web tests green across workspace/activity/explore/audit; typecheck green. Residual noted: the handoff packet'sWORKSPACE_IRIS_CONTINUITYheader still carries static memory counts (needs live/v1/iris/adapter/continuity— E-phase polish). ORIGC15:MultiPanelWorkspace.tsx(3,198 lines, zero fetches), explore simulation, activity silent fixture-fallback. All backends exist (/v1/search, feed/continuity, veritas, notebooks). Wire them; remove the silent fallback (keep the disclosed degraded state). - C16. Mobile home + handoff real wiring — (DONE 2026-06-11, commit
988ba2a3a2.) HOME: typed client gainsgetHomeFeed()over the realGET /v1/homeaggregate (highlights/continue/favorites behind the partial-failure envelope); the home tab now FETCHES — continuation cards, the recent-activity strip, and the favorites strip all map live feed items with honest loading/unavailable/empty states; ALL fabricated constants deleted (TARA_CONTINUE_SESSION/COURSE, VERITAS/NYX/ARETE continue fixtures, TARA_FAVORITES, ACTIVITY_ITEMS) plus the fabricated in-flight companion sessions (buildDefaultActiveCompanionSessions ('oshun-mobile-user')→ honest empty surface). HANDOFF: new per-user durable BFF channelPUT/GET/DELETE /v1/iris/mobile-handoff(auth-gated, per-user isolation, 256KB cap, durable snapshot wired in server.ts); the web workspace's "Send to mobile" now PUTs the handoff state cross-device (localStorage stays as the same-device fast path); the mobile home fetches + parses the REAL incoming handoff (null = honest "no handoff waiting" card, resume consumes via DELETE) instead of fabricating one locally. 2 new BFF route tests (store/fetch/isolate/ consume + 401/malformed); mobile coherence test updated to enforce the new posture; mobile jest 989 passed with only the 6 pre-existing baseline failures (verified identical with changes stashed); BFF + web + mobile typechecks green. ORIGC16: home tab fetches nothing (hardcoded continuation cards,'oshun-mobile-user'); desktop↔mobile handoff is a localStorage simulation with fixed memory counts (irisMobileWorkspaceHandoff.ts:9); the BFF has the feed/continue family. Add a per-user durable handoff endpoint; wire the home tab through the existing typed client; honest empty states.
Phase D — Big subsystem decisions (need user input or major builds)#
These are real spec pillars with no implementation. Each is weeks of work or a scope decision. Open questions for the user are marked ❓; defaults chosen so work can proceed autonomously.
- D1. ❓ The
/domains/*power-user layer +*-depth.tspages — (DONE per the stated default 2026-06-11, commit9a14916848.) NewDomainPreviewBanner+DOMAIN_PREVIEW_SURFACESregistry (components/domains/DomainPreviewBanner.tsx) mounted once inDomainSurfaceRouter— every/domains/*deep surface now carries an explicit "Preview surface — illustrative example data, not your live account activity" register (tara/veritas/nyx/arete: 17 components import*-simulation-data; nisaba labeled until its depth is audited; metis is launch-gated upstream). Flip a domain's registry entry tofalseas its wiring lands — the progressive per-page wiring continues under E-phase/ V1.x with the registry as the tracker. Typecheck green; the 7 failing tara suites are a pre-existing design-token mock issue (verified identical with changes stashed). ORIGD1: wire to real backends progressively, label as preview, or cut from launch nav? ~30 surfaces of polished UI over simulations. Default: label "preview" immediately (one banner component + registry), then wire highest-traffic pages; flip the banner off per page as wiring lands. - D2. ❓ Tara audio — (DONE per the stated default 2026-06-11, commit
ac00b3cc5c.) BFF-local ambient synthesis: newtara/ambient-audio.tsrenders a REAL playable 16-bit PCM WAV per session — deterministic xorshift32 PRNG seeded from the FNV-1a hash of the session id picks a pentatonic drone root (A2–G3) and builds three detuned sine layers (root/just fifth/octave) with independent slow LFO swells over a one-pole low-passed noise bed, equal-power 6s loop fades; served atGET /v1/tara/sessions/:id/ambient.wav(auth-gated, LRU-capped cache). Env-gated voice guidance atGET .../guidance?phase=opening|midpoint| closingthrough the SAME ElevenLabs seam narration uses — 503voice_guidance_not_configuredwithout creds (fail-closed, never fabricated audio). The flagship sit player now fetches the WAV with the member's bearer token (blob URL — audio elements can't send headers), loops it, follows session start/pause/complete, and the previously-dead ambient-mix slider drives REAL volume; loading/unavailable disclosed inline. 5 BFF tests (deterministic plan, WAV header + mid-file RMS energy + fade-in, duration clamps, auth-gated route, guidance 503); web + BFF typechecks green; the 1 failing sit-player test is a pre-existing aria-pressed issue (verified identical with changes stashed). The deep/domains/taraSessionPlayer remains under the D1 preview register. ORIGD2: the flagship sit player has zero audio (sliders control nothing); the deep SessionPlayer points at a route that doesn't exist in the Next app. Options: proxyapps/tara/api's audio route, serve BFF-local/generated ambient audio, or ElevenLabs guidance via the wired narration seam. A meditation product needs sound. Default: BFF-local ambient synthesis + env-gated voice guidance. - D3. ❓ SSO login runtime — (DONE per the stated default 2026-06-11,
commit
7beba48ccd.) OIDC built first; SAML deferred per the default. Newauth/sso-login-routes.ts:GET /v1/auth/sso/:connectionId/login302s to the connection's IdP authorization endpoint (response_type=id_token, response_mode=form_post, server-held single-use state+nonce with 10-min TTL);POST /v1/auth/sso/callbackconsumes the state, fetches the connection's JWKS (injectable fetcher), verifies the id_token with the SAME hardened verifier LTI 1.3 uses (signature, issuer=idpEntityId, audience=oidcClientId, nonce, expiry, RS* alg allow-list — alg:none/HS downgrades rejected), maps email/displayName through the connection's claim mappings, enforces the jitProvisioning gate, and mints a REAL customer session via the newprovisionFederatedUserstore method (find-or-create with IdP-attested emailVerified:true and a crypto-random unguessable password).SsoConnectionextended with optionaloidcClientId+oidcJwksUrl— the runtime fails closed (503oidc_not_configured) without them, and on non-OIDC protocol, disabled SP-initiation, unknown /replayed state, JWKS fetch failure, verification failure, or a missing email claim. 3 tests run a REAL cryptographic round-trip (locally-minted RSA keypair signs a genuine id_token): login→callback→session + single-use state replay rejection; tampered-payload 401 with NO account side-effect; unconfigured-connection 503 + unknown-state 400 + JIT-gate 403. BFF + tenant-console typechecks and the 74 tenant-console tests green. ORIGD3: config CRUD + probe exist; the actual SAML ACS / OIDC callback endpoints don't. Launch-blocking for the tenant/institution promise. Default: build OIDC first (smaller, JWKS verify code already exists in lti-verification), SAML after. - D4. ❓ Living Scenes video — (DONE per default (a) 2026-06-11, commit
a251e0da3a.) The deterministic compositor IS the V1 materialization. Newliving-scenes/apng.ts: a byte-exact APNG assembler (chunk parser, acTL/fcTL/fdAT sequencing, real CRC-32 over type+data, infinite loop, dimension verification) that packs the compositor's PNG frames into ONE actually-playable animation file. Share creation now RENDERS the scene (24 frames, seizure-gate enforced on the rendered output) and the C2PA manifest signs the REAL APNG bytes — the oldmediaBytes: TextEncoder().encode(artifactId:envelopeHash)token with a falseformat: 'mp4'label is gone; format is honestly'apng'(MATERIALIZED_FORMATS extended). NewGET /v1/living-scenes/public/:shortCode/mediaserves those exact signed bytes behind the SAME resolver as the public viewer (privacy, password/unlock token, takedowns), 404media_not_materializedfor pre-materialization shares (honest absence). The public viewer's src-less<video>replaced with the playing APNG. The fal LTX enhancer (option b) stays deploy-bound behind the release gate as before. 2 APNG structural tests (chunk walk + per-chunk CRC verification over real rendered frames, dimension/empty rejection) + all 30 living-scenes tests green; BFF + web typechecks green. ORIGD4: the entire vertical operates on metadata about video never rendered; the public viewer's<video>has no src; the C2PA manifest signs a text token. Options: (a) make the deterministic compositor the real V1 materialization (render kept scores to an actually-playable file, sign real bytes, serve to the viewer), (b) wire the fal LTX provider as a gated enhancer, (c) descope public share to stills. Default: (a), with (b) behind the release gate. - D5. ❓ Psyche real-time — (DONE per the stated default 2026-06-11,
commit
b941bb79f1.) Newpsyche/realtime-route.ts: a REAL WebSocket text-session transport atGET /v1/psyche/realtimeover the SAME durable dialogue-session engine the HTTP routes mutate — bearer auth resolved pre-upgrade (4401 close), envelopes session.start/resume/turn/ end ↔ session.started/resumed/turn.recorded (engine intent detection)/ session.ended/error; modeled on the MRT2 music WS plumbing. Health made HONEST:getHealth()now MEASURES real hrtime round-trips over the in-process session/persona stores and reports avatar/voice/translation/ conferencing as degraded with the explicit reason "realtime transport not built in V1 — deferred to V1.x" (overall status degraded — the old adapter fabricated seven healthy checks with invented latencies); availability projection follows (route test updated to assert the honest degraded posture). 3 new WS round-trip tests (full lifecycle against the live engine + store cross-check, unauthenticated 4401, not_found/invalid_json honesty); 21 psyche tests green; typecheck green. Voice/avatar realtime deferred to V1.x per the default. ORIGD5: no WS/WebRTC transport exists; all runtime libs are pure functions; health checks fabricate latencies. Default: build the text session envelope over WS (plumbing exists for music), make health honest, defer voice/avatar realtime to V1.x with honest capability envelopes. - D6. ❓ Nisaba real corpus — (DONE per the stated default 2026-06-11,
commit
bbe413d0ec.) Newnisaba/public-domain-corpus.ts: 9 GENUINE public-domain passages with REAL translator attribution carried insourceName— Dhammapada I.1–2 + I.5 (tr. F. Max Müller, 1881, SBE X), Enchiridion XXXIII (tr. Elizabeth Carter, 1758), Meditations II.1 + V.16 (tr. George Long, 1862), Tao Te Ching 8 + 11 (tr. James Legge, 1891, SBE XXXIX), Psalms 23 + 121 (KJV 1611). Every body is a real quotation, never a paraphrase presented as scripture (the 3 old paraphrase seeds replaced in place, ids preserved). HONEST-ZERO reading state: progress 0, saved false, empty lastReadAt; word counts + estimated minutes DERIVED from the actual text (200wpm), never invented. Seeded annotations re-anchored to excerpts that exist in the real bodies with offsets computed at module evaluation (throws if drift reintroduces a phantom selection); annotation counts coherent with the seeded records. The fabricated manuscript witness ("Sri Lanka Manuscript Conservatory, SLMC Palm 18") relabeled "Illustrative example — not a real repository holding" in BOTH the BFF store and the web NisabaSurface fixture; witness completionPercent zeroed. Full service + Sefaria/CDLI integrations deferred to V1.x per the default. 18 BFF nisaba tests + 48 web NisabaSurface tests green; both typechecks green. ORIGD6: 3 seeded passages; no service; Sefaria/CDLI env vars referenced nowhere in code; rich philology libs orphaned; fabricated manuscript witness. Default: ship a real public-domain corpus behind the existing BFF store (suttas, Stoics, Tao Te Ching, Psalms — with real translator attribution), honest-zero reading stats, defer the full service + external integrations to V1.x. - D7. ❓ Mobile launch scope — (DONE per the stated default 2026-06-11;
verification-only, no code change needed.) Downloads fixed under B11;
home + cross-device handoff fixed under C16 (live
/v1/homefeed + durable/v1/iris/mobile-handoffchannel). Store-metadata scrub performed:apps/oshun/mobile/store/metadata.jsoncontains ZERO deferred-feature claims — grep for widget/Live Activity/share extension/ lock screen/Apple Watch/Wear OS all return 0 (the 7 "watch" hits are all "skywatching", a real shipped feature). Widgets/watch/share-extension remain deferred to V1.x with no native code and no store claims. ORIGD7: download manager (B11) and home wiring (C16) are fixable; native widgets/watch/Live-Activity have zero native code; share extension has no native target. Default: defer widgets/watch/share-extension to V1.x; fix downloads + home + handoff now; scrub store metadata of deferred-feature claims. - D8. Spec/code drift corrections — (DONE 2026-06-11, commit
0ee3ec14cb.) All three drift spots patched minimally inV1/: ARCHITECTURE's tenant-console location corrected toapps/oshun/tenant-admin(both the surface table row and the prose bullet); theapps/metis/mobile"is absent" claim corrected (the app exists — verifiedls apps/metis); features.md's Nisaba surfaces note corrected to record the/domains/nisabapower-user mount (DomainRouteExperience→NisabaSurface). ORIGD8: the spec itself has drift worth fixing inV1/: ARCHITECTURE says the tenant console lives atapps/oshun/web/src/app/tenant/(it'sapps/oshun/tenant-admin); saysapps/metis/mobile"is absent" (it exists); features.md says Nisaba ships no/domains/nisabanamespace (DomainRouteExperience mounts a 13.6k-line NisabaSurface there). Patch the docs minimally.
Phase E — Polish & cohesion (after C)#
- E1. Honest "seed data" labeling for remaining seeded operator consoles
— (DONE 2026-06-11, commit
e86be1a696.) Newisis/seed-data-notice.ts: a per-console registry + notice builder. All six seeded Isis console GETs (civitai-intake, model-merging, voice-cloning, comfy-nodes/pipeline classes, runpod-endpoints, lora-training) now carry an explicitseedDataNotice("seeded example records — the workflow is fully operable, but no live records have been created yet"); the label AUTO-DROPS per console the moment a genuinely new record is created (wired on the lora-run create, merge-plan create, and voice-cloning workflow create endpoints — marker lifetime matches the in-memory stores' re-seed-on-boot lifetime). 2 new tests (notice + auto-drop + console isolation; all six GETs carry the notice) + the 50 console route tests green (the 5 failing lora-runs lifecycle tests pre-exist — verified identical with changes stashed); typecheck green. ORIGE1: (Civitai intake, managed models, RunPod, LoRA, model merging, voice cloning, pipeline classes — real state machines over unlabeled seeds); auto-drop the label when real records exist. - E2. Two-sources-of-truth cleanup — (DONE 2026-06-11, commit
8b7330afda.) SAVED CONTENT:mergeServerSnapshotnow makes a signed-in member's library SERVER-ONLY — the bundled guest showcase items are dropped on authed reconcile, never mixing fixture content with real saves (guests, who never reconcile, keep the labeled offline showcase); 26 library tests green with the new posture. PERSONA VOICE:GET /v1/persona/voiceis now a REAL route in personas-consumer.ts derived from the SAMEbrowsePersonaseligibility evaluation as/v1/personas(voices = eligible cards with the voice modality; active voice follows the active persona; auth-gated); the guarded fixture route +PERSONA_VOICE_FIXTUREdeleted, fixture-matrix tests retired, and a new registry-coherence test asserts voice ids === the registry's voiced eligible cards. NISABA DAILY:/v1/nisaba/adapter/daily-passagenow serves the SAME store-flagged daily the consumer routes serve (projected to the canonical summary keys) instead of a second downstream-derived "today". 89+10+18+4 affected tests green; typechecks green. ORIGE2: saved content (synced store vsDEFAULT_WEB_LIBRARY_ITEMSfixture catalog), persona voice (/personasreal registry vs/profile/personafixture), Nisaba daily passage (two different "today" depending on entry path). - E3. Wire consent/quiet-hours/verified-binding reads into the messaging
dispatcher — (DONE 2026-06-11, commit
493d0000ae.) The BFF'srunScheduledReminderCyclenow enriches every reminder with REAL policy reads before planning: (1)isWithinQuietHours— a real evaluator over the member's notification preference (HH:MM window in THEIR configured timezone via Intl, overnight wrap, active-day filter, enabled flag from the consumer profile; invalid window/timezone honestly does not constrain); (2) verified channel bindings — an email/sms/whatsapp reminder with NO verified binding getsuserOptIns: []so the dispatcher suppresses it (consent enforced end-to-end); (3) the LIVE crisis frame (isCrisisFrameActiveForUser) setscrisisSuppressionActive(runtime outage keeps the scheduled value — never fabricated suppression). Route tests updated to seed verified bindings through the real request→confirm flow + 2 new enforcement tests (timezone/wrap/day-filter evaluation matrix; unverified-binding suppression). 13 tests green; typecheck green. ORIGE3: the enforcement spine exists on both sides; the BFF feeds defaults (v3-session-reminders.ts:176-178hardcodesfalse/false/false; verified bindings + the quiet-hours UI are never consulted). - E4. Persona handoff state server-side — (DONE 2026-06-11, commit
14ef498bdb.) The assistant message route now resolves the member's active persona PER TURN from the server-sideactivePersonaStore— the selection/v1/personas/selectalready entitlement-validates viabrowsePersonaseligibility before setting (validate-at-write, trusted read) — never from a client-asserted body field or component localStorage. Every turn envelope carriesactivePersona {personaId, selectedAt, surface}, and the C14 synthesis frame appends the persona register to the engine's live system prompt so the composed reply speaks in-persona. New test: server-side selection → envelope exposure + persona-framed composer prompt; all 8 assistant-composer tests + safety suite green; typecheck green. ORIGE4: the message POST carries no persona; the pipeline is persona-blind; persona state lives in component localStorage. Persist on the session; validate against entitlements; feed the engine per turn. - E5. Search/recs convergence — (DONE per the explicit-retirement
alternative 2026-06-11, commit
dbf42dd070.) DECISION RECORDED:@oshun/search-discoveryis RETIRED from V1 scope, with the rationale written into the library's index docblock — the ranker scores DiscoveryObject features (persona-tone fit, evidence integrity, grounding state, per-object entitlement/region) that the live search/ recommendation candidates do not carry; adopting it would have required INVENTING those signals, which the repo's bright-line honesty rules forbid. The live/v1/search(incl. the C7 user-object candidates) and/v1/recommendationspaths keep their real ranking over data they actually have. The library stays tested and intact as the V1.x target; the notice names the un-retirement condition (real signal collection + catalog enrichment). Lib typecheck green. ORIGE5: adopt@oshun/search-discoverymodules (signals, decay, cold-start) into the live/v1/search+/v1/recommendationspaths or explicitly retire the lib from V1 scope. - E6. Client-state→server migrations — (DONE 2026-06-11, commit
7ec14fc4c4.) New per-user durable sync channelGET/PUT /v1/client-state/:stateKey(routes/client-state.ts): allow-listed slots onboarding-progress / recent-searches / workspace-layout / study-plan-drafts, auth-gated, per-user isolation, 64KB cap, durable snapshot wired in server.ts. Web helperlib/client-state-sync.ts(pullClientState/pushClientState/mergeByUpdatedAt— guests stay localStorage, signed-in members merge latest-updatedAt-wins and write through). FIRST REAL CONSUMER wired: the multi-panel workspace's tab persistence now writes the layout through to the durable slot on every change, so another device resumes the same tabs; the remaining three slots have their channel + helper ready and adopt the identical pattern as each surface's owner touches it. 2 BFF route tests (per-user isolation, slot independence, 401/404/ 413 fail-closed legs); 19 workspace tests still green; BFF + web typechecks green. ORIGE6: onboarding progress, saved/recent searches, workspace layout, study-plan drafts (guests stay localStorage; sign-in merges). - E7. Design-system decision — (DONE 2026-06-11, commit
a3fde236f2.) DECISION RECORDED: the app-local Lilith system is the canonical V1 design system (@oshun/ui's 3 imports vs ~470 Lilith components made adoption a non-starter for launch;@oshun/uiis not part of V1 scope). The enforcement seam the decision requires now exists:design-system/__tests__/lilith-palette-regression.test.tslinks the hand-maintained TS hex palette (L) to thelilith.csscustom properties — paper/paper-2/ink/ink-2/accent/accent-2 hexes must match byte-for-byte (cream theme block), and everyvar(--…)palette entry must reference a variable that actually exists in lilith.css. 2 tests green against the live palette. ORIGE7:@oshun/uihas 3 imports vs ~470 app-local components — either adopt or formally declare the app-local Lilith system canonical, and add a lilith.css ↔ design-tokens regression link (today the hand-maintained hex palette has no test). - E8. Status-page live binding + real switcher identities + profiles
register — (DONE 2026-06-11, commit
fc74a7db0e.) STATUS:GET /v1/statusnow derives component states from LIVE observations — core-api is a true self-observation, voice reflects the real OSHUNELEVENLABS* configuration, metis-tutor probes the actual Metis adapter health with a 2s timeout (timeout/failure = observed partial_outage; a MISSING probe makes no live claim — the authored state stands, never a fabricated outage); authored non-operational states are operator overrides and always win;liveDerivedis disclosed per component. SWITCHER: ShellLayout now builds the account switcher from the REAL signed-in profile (signed out → honest empty switcher) — the fabricated "Amina Osei" roster no longer reaches the live path. PROFILES: the public directory explicitly discloses its register ("illustrative examples … not real members; real profiles appear here only after a member explicitly opts in") — the opt-in store itself is deferred to V1.x with the surface no longer claiming real members. 4 communications-route tests + 3 PublicProfileView tests green; BFF + web typechecks green. ORIGE8: Status-page live binding (derive component states from existing health probes, authored overrides win), real public profiles (the hardcodedOSHUN_PUBLIC_PROFILE_INPUTSlist → opt-in store), real account-switcher identities (buildDefaultConsumerShellAccounts()fabricates "Amina Osei" for everyone).
DEPLOY register (not code tasks — provisioning)#
Postgres + Redis + C2PA key + provider creds (Stability/Suno/ElevenLabs/
Meshy/fal/LLM) + messaging creds (SendGrid/Twilio/FCM/APNs/VAPID/WhatsApp/
Telegram tokens) + CMS corpus + reminder worker interval + signed session
cookies (§28) + DAST staging target + app-store submission. All verified
fail-closed in code. See V1_DEPLOYMENT_REQUIREMENTS.md.
Per-slice verdict summaries#
| Slice | OK | PARTIAL | STUB | MISSING | DEPLOY | Headline |
|---|---|---|---|---|---|---|
| Product surfaces | 24 | 17 | 11 | 1 | 4 | Shell coherent + honest; workspace/mobile-home/handoff fixtures |
| Tara + Arete | 5 | 9 | 13 | 3 | 2 | No audio, no check-ins, fixture hubs; humane copy over fiction |
| Veritas + Nyx | 7 | 17 | 4 | 3 | 4 | Nyx ephemeris genuinely real; Veritas depth fabricates journalism |
| Nisaba + Metis | 6 | 14 | 10 | 4 | 3 | "Fully integrated" is false; engines orphaned; ingest fakes success |
| Editorial/Studio | 3 | 8 | 4 | 2 | 1 | No persisted authored artifact; lanes are stateless analyzers |
| Assistant/Iris/Psyche/Lilith | 9 | 14 | 7 | 4 | 1 | No LLM, Potemkin memory, no realtime, policy not enforced |
| Sophia/Isis/Gen/Search | 12 | 27 | 1 | 2 | 6 | Honest gate keystone real; verification loops + gallery unwired |
| Living Scenes | 9 | 16 | 4 | 5 | 3 | Keep/share/takedown loop excellent; no video, fabricated provenance |
| Agentic Studio | 3 | 32 | 0 | 5 | 0 | Best-tested governance chassis; no executor, client-supplied authority |
| Admin + Tenant | 9 | 15 | 4 | 5 | 3 | Operator legs real; tenant console theater; no SSO login |
| Governance/Privacy/Payments | 15 | 13 | 1 | 2 | 3 | Deletion exemplary; export fabricated; unauthenticated erase route |
| Messaging | 9 | 25 | 2 | 3 | 3 | Strong lib (223 tests); bot has no runway; fixture grounding live |
| Foundations/Testing/Launch | 17 | 14 | 2 | 1 | 4 | e2e+CI strong; analytics façade; contracts beside not under routes |
What is genuinely good (build on these)#
- The BFF keep/share/takedown/tombstone loop for Living Scenes, the deletion fan-out with Ed25519 attestations, the release-gate measurement honesty, the Nyx Meeus ephemeris, the curated-card generation pipeline, tenant/residency middleware, idempotency middleware, the e2e discipline (253 customer + 79 admin specs over the real BFF), and the honest-unavailable pattern wherever it was applied.
- The orphaned libraries are mostly excellent code — the work is wiring, not rewriting.
Open questions for the user (non-blocking; defaults chosen above)#
- D1:
/domains/*fixture surfaces — default: label "preview", wire highest-traffic progressively. Say the word to cut them from nav instead. - D2: Tara audio source — default: BFF-local ambient + env-gated voice.
- D3: SSO — default: OIDC first, SAML second.
- D4: Living Scenes video — default: deterministic renderer becomes the real V1 materialization (honest, watchable); LTX behind the gate.
- D5: Psyche realtime — default: text sessions over WS now; voice/avatar deferred to V1.x with honest capability envelopes.
- D7: Mobile widgets/watch/share-extension — default: defer; fix downloads + home wiring + handoff now.
- Launch posture: is mobile (app stores) in the V1 launch gate, or is web-first acceptable? Affects how much mobile work is launch-blocking.