Date: 2026-05-28 Scope: The entire V1 implementation as specified in
V1/{ARCHITECTURE.md, features.md, TODOS.md, DEPENDENCIES.md}, audited against
the code under apps/oshun/*, apps/metis/*, libs/oshun/*,
libs/contracts/*, libs/{sophia,nisaba,metis,themis,yemaya,aje}/*, and
libs/shared/*. Method: 24 parallel adversarial code audits (two-pass:
confirmatory coverage map + stub hunt + test-coherence check), each reading the
actual source and running the project's mandated stub-indicator grep. Findings
below are backed by file:line evidence.
1. Executive Verdict#
Oshun V1 is NOT production-ready. It is, however, much closer to ready in its domain logic than in its integration, and the gap is unusually uniform.
The single most important finding:
The domain-logic libraries are real, deep, domain-specific, and well-tested. The product is not wired together. Across nearly every subsystem, the
libs/oshun/*substrate computes the correct decision (a recall ranking, a crisis classification, a budget verdict, a release-gate pass/fail, an entitlement) as a pure function — and then nothing consumes that decision at runtime. Persistence is in-memoryMaps, domain adapters point at backends that don't implement the contracted routes, and the customer/operator surfaces are fed hardcoded fixtures, several of which are actively dangerous.
This is a good position to be in (the hard algorithmic work is largely done and verified) but it means the remaining work is integration, persistence, and a few genuine engine builds — substantial, multi-team, multi-week effort, not a finishing pass.
A blunt summary of the three failure classes:
- Wiring gaps (most of the codebase). Real logic, no runtime consumer / no
concrete adapter / no persistence. Examples: Iris memory, Lilith crisis
classifier, Isis generation gates, Agentic-Studio budgets & kill-switches,
Studio release gates, Trust-Safety queues, Billing-Support, the whole admin
BFF (in-memory
Map, no DB). - Genuine fabricated-code stubs (a handful, but serious). Code that returns invented results: Metis worker analytics/reports (seeded-RNG fake metrics), Metis research-agent (fabricates sources — directly violates a stated requirement), Yemaya render core (simulated rendering + fabricated telemetry, no pixels), Living Scenes (no render/blend kernel, faked C2PA signature, watermark embedding absent, takedown cascade mutates nothing), Privacy DSAR/deletion (soft-flag only; cryptographic-shred flag copied from input), Veritas retraction cascade (in-memory planner, never cascades), and synthetic on-chain deposit addresses for Tron/TON/Ergo/Cardano.
- Dangerous fixtures shipped to real surfaces. The BFF
domain-stubs.tsand weblilith-data/*fixtures render fabricated data with200 OKon production surfaces: a dead crypto receiving address for payments, hardcoded consent/memory-pause state (compliance hazard), fabricated audit logs / SSO connections / incidents shown to operators as authoritative, fabricated astronomy onnyx/tonight, and a fabricated "verified" news claim from a fake source on the Veritas home briefing.
2. Readiness Scorecard#
Legend: ✅ Production-grade (within audited scope) · 🟡 Real logic, blocking gaps · 🔴 Not ready / contains fabricated code
Customer-facing domains#
| Domain | Verdict | Headline gap |
|---|---|---|
| Tara | ✅ | Logic + contracts production-grade. Only minor: 4-week-only plan limit, dead branches. |
| Arete | ✅ | Real humane streak/recovery + friction/intervention engines; full contracts; coherent tests. |
| Nisaba | ✅ | Strongest domain. Real in-repo morphology (9 ancient languages), concept graph, lexicon, study plans. |
| Veritas | 🔴 | Retraction cascade is an in-memory planner that never cascades (no route/event/Sophia invalidation); contradiction loop + Sophia grounding are interface-only. |
| Nyx | 🟡 | Real ephemeris built + wired: Meeus sun/moon position, phase, rise/set, alt/az (ephemeris.ts, Meeus-verified); nyx/tonight now serves REAL computed sky (buildNyxTonightCard) — the BFF route + fixture are gone. Remaining: the 19 power-user depth pages. |
| Metis | 🔴 | The named "7 release gates" pipeline doesn't exist as a gate; api-gateway proxies to an out-of-repo Python backend; worker analytics/reports/exports are seeded-RNG fakes; research-agent fabricates sources. |
Platform substrates#
| Substrate | Verdict | Headline gap |
|---|---|---|
| Sophia | ✅ | Contract/transform layer correctly delegates to real libs/sophia/*. Follow-up: per-query source-set scope confinement deferred to backend (spec calls cross-set leakage a hard fail). |
| Search & Discovery | ✅ | Genuine BM25/cosine/NDCG/IR + deterministic A/B; the strongest test suite in the audit. |
| Psyche | ✅ | Pure policy/contract layer is production-grade (real turn-taking, ARPABET visemes, reconnect). Live WS/WebRTC transport lives in out-of-repo services/psyche/*. |
| Persona Registry | ✅ | 1422 tests; real role-inheritance algebra, abuse scorecards, impersonation detection. |
| Lilith | 🟡 | All safety logic real & tested, but the rich crisis classifier is not wired into its own adapter (adapter depends on an unimplemented injected analyzeSafety). |
| Iris | 🟡 | Real consent/recall/deletion logic. Durable revision-chain persistence now built (DurableMemoryStore over iris_memory_entry_revision; §8), incl. a real forget hard-purge for DSAR. Remaining: wire the adapter to live surfaces (consumer is still a localStorage demo). |
| Isis | 🟡 | Gate enforcement genuinely blocks dispatch and is tested — but the library has zero importers, no tsconfig alias; not wired to any surface. Tier resolver / surface guard / LoRA training absent. |
| Aje / Payments | 🟢 | No fabricated settlement, and all four non-EVM rails (TRON, Ergo, TON, Cardano) now derive real, chain-valid watch-only deposit addresses (keccak/base58check, blake2b-256/base58, v4r2 StateInit hash, CIP-19/bech32; each verified against authoritative per-chain vectors/oracles; §8). The synthetic-address gap is closed. |
Surfaces, shell, studio, governance, foundations#
| Subsystem | Verdict | Headline gap |
|---|---|---|
| Consumer Shell (shell-core/-assistant/-routines/-achievements/-desktop/-wearable) | ✅ | Real cross-domain ordering, NLU, Iris bridge; 1563 tests. Only 2 hollow wearable complications (data-model gap). |
| Foundations (domain-registry, persistence, platform-foundations, navigation, offline, i18n, contracts) | 🟡 | Overwhelmingly real (85-model Prisma schema + real migrations, OAuth/PKCE, durable queue, event-bus w/ HMAC). One defect: broken @veritas/contracts tsconfig path (empty dir). |
| Themis (academic-integrity adjudication) | ✅ | Real deterministic adjudication engine; calibrated policies; Metis contract bridge; coherent tests. |
| Auth | ✅ | Real signed-JWT verification (alg-pinned, timing-safe), prod-hardened, RBAC denies, no bypass, no hardcoded secrets. One pre-GA action: confirm edge proxy strips inbound x-oshun-tier headers. |
| Studio + Curation | 🟡 | All 11 areas real (Flesch, DFS cycle detection, Myers/LCS diff, CNF rules), but the findings→publish-gate loop is open and nothing persists/enforces at runtime. |
| Agentic AI Studio | 🟡 | High-quality governance primitives (SSRF guards, z-score anomaly, BFS revocation), but no orchestrator consumes them; killed isn't even a run status; budgets/kill-switches decide but never act. |
| Tenant Console | 🟡 | Library production-quality (RFC-4231-correct HMAC, xAPI/Caliper, hash-chain audit). But forgeable unsigned session token; LTI 1.3/SCORM missing; SAML/OIDC signature verification assumed-upstream. |
| Messaging Channels | 🟡 | Real Telegram crypto (initData/login HMAC) + real grammY delivery + tier routing. But only Telegram delivers (Email/Push/SMS/WhatsApp are payload-only); bot voice STT is a placeholder; @noble/hashes skew breaks bot tests. |
| Billing-Support | 🟡 | Real entitlement/proration/tax/dunning/metered logic, but not wired to Aje or any app — an island with a parallel entitlement model. |
| Trust-Safety | 🔴 | Real decision functions, but pure functions with no queue/audit-platform wiring; the crisis-frame cascade does not exist as propagation (a named exit criterion). |
| Privacy | 🔴 | DSAR/deletion does not enforce — soft-flag only; cryptographicShredApplied is copied from caller input; no cross-domain tombstone fan-out. The one subsystem that must enforce, doesn't. |
| Analytics | 🟡 | Real event-collection SDK; no fabricated metrics (clean). But recommendation-observability & offline-eval exist only as declarative manifests — no aggregation/eval engine. 14.5k LOC of out-of-scope V3 bloat. |
| Living Scenes | 🔴 | Governance/lifecycle control plane is real, but no render/blend pipeline exists, C2PA signature is faked (SHA-256, not Ed25519), watermark embedding absent, takedown cascade mutates nothing, no persistence. |
| Yemaya (render substrate) | 🟡 | A real raster kernel + composition renderer + an orchestrator render path now exist: raster-kernel.ts (W3C source-over + separable blend modes, genuine separable Gaussian blur, radial vignette, multi-layer stack), rasterizeComposition(Composition) (scene-model solid layers → actual RGBA8 pixels with anchor/rotation/scale fidelity), and RenderCore.renderComposition (produces pixels + measured metrics; executeJob is now the cost planner), with anti-aliased rotated edges, a 12-effect per-layer pass, and a real server-side PNG codec (decode/encode RGB+RGBA, all 5 filters, CRC-checked, node:zlib via dynamic import so the browser bundle is unaffected) — all known-answer verified (§8). Remaining: GPU/wgpu acceleration, wiring decoded textures into the composition (texture sampling), and text-shaping (font engine). Conductor/scheduling & vector/SVG/text primitives are real. |
| Oshun BFF | 🔴 | Real auth/adapter/middleware skeleton, honest 503s on live customer routes — but the data plane is fixtures: 31 pure-fixture GETs, no idempotency middleware (spec-mandated), in-memory rate limiting, dangerous fabricated payloads. |
| Oshun Web (consumer) | 🔴 | All 6 canonical domain hub pages render hardcoded fixtures with no BFF call; two surfaces fabricate convincing data on failure (sky events; a "verified" news claim); profile/memory & power-user Arete persist to localStorage only. |
| Admin Web + Mobile | 🟡 | ~10 of 14 workflow areas operationally wired (privacy/review/incident/model/persona/rights/research-integrity/editorial). But Trust&Safety has no moderation actions, Support/Billing has no refund/credit/entitlement actions, Metis governance is absent, and the entire admin BFF is in-memory, no DB. |
3. BLOCKERS (P0 — fabricated code or dangerous behavior on a live surface)#
These are not "missing features" — they are code that returns invented results or ships harmful data. Every one would fail the project's own adversarial-verification bar.
- BFF returns a dead crypto receiving address.
apps/oshun/bff/src/routes/domain-stubs.ts:~1664—POST /v1/payments/crypto/quotereturnsreceivingAddress: '0x000000000000000000000000000000000000dead'with200. A customer following the crypto-pay journey is handed a burn address. (Financial.) - BFF fabricates consent / memory-pause / audit / SSO / incident data with
200 OK.domain-stubs.ts—GET /v1/data-rights/consentandGET /v1/memory(paused:false) return hardcoded privacy state (compliance hazard);GET /v1/audit,/v1/sso,/v1/incidents,/v1/user-reportsreturn fabricated/empty data rendered directly by the operator console as authoritative. (Compliance / operational integrity.) - Web fabricates astronomy and "verified" news on backend failure.
apps/oshun/web/src/lib/server/nyx-depth.ts:74-97(tonightFixture()invents sky events);apps/oshun/web/src/components/home/homeVeritasBriefingModels.ts:110-176(FALLBACK_HOME_BRIEFINGpresents a fabricated claim withverdict:'verified'from a fake source). Distinguished only by a subtle pill. (Trust — directly inverts the V1 "visible grounding state" promise.) - Metis worker analytics/reports/exports are seeded-RNG fakes.
apps/metis/worker/src/jobs/analytics-jobs.ts:254-298,report-jobs.ts:755-924,course-export.ts:834— every metric (activeUsers,completionRate, retention cohorts, exported course content) is invented from a hash-seeded RNG that ignores real inputs. (These are launch-blocking learning-telemetry surfaces.) - Metis research-agent fabricates sources.
libs/metis/agents/src/agents/research-agent.ts:256-268— manufactures a source list (Author A/B/C, inventedrelevanceScore/reliabilityScore). The spec explicitly requires fabricated-research blocking; this does the opposite. - Privacy DSAR/deletion does not delete.
libs/oshun/privacy/src/export-deletion/deletion.ts—cryptographicShredAppliedis copied frominput.canShred; no data is touched, no tombstones written.dsar.tsmarks scopes complete from an operator-supplied verdict;consent.ts planWithdrawalCascadereturnspendingsteps that never execute. The spec's mandated cross-domain tombstone fan-out (ARCH §1760-1794) does not exist. - Veritas retraction cascade never cascades.
libs/oshun/domain-veritas/src/retraction-cascade.ts:73-127is a pure in-memory planner; there is no retract route, no event publish, no Sophia evidence-pack invalidation anywhere in the repo. The only caller is a web component feeding hardcoded fixtures. - Yemaya render core simulates rendering.
libs/yemaya/rendering-pipelines/src/render-core/render-core.ts:1503("Simulate stage work"), fabricateditemsProcessed/memUsed/frameCount:1/outputSizeBytes;visual-compositor.ts:822blur "simulates gaussian blur via value damping" on a single color. No pixel buffer is ever produced; no Rust/wgpu/GPU/canvas kernel exists. - Living Scenes has no render/blend pipeline and faked provenance.
Conductor dispatches nothing; Blend Kernel performs no blending; the wired
C2PA "signature" is
sign = stableHash(SHA-256, not Ed25519/X.509); audio/visible watermark embedding is absent; takedown dispositions mutate nothing; persistence is in-memoryMaps. The PSE/strobe live-frame safety killer (a hard no-override requirement) is unimplemented. - Synthetic on-chain deposit addresses (Tron/TON/Ergo/Cardano).
chains/tron/src/node-client.ts:148-164,chains/ton/src/subwallet.ts:94-122,chains/ergo/src/p2pk-allocator.ts:8-11,chains/cardano/src/node-client.ts:88— per-invoice addresses aresha256-derived "synthetic, base58-like" strings, not chain-valid. A customer paying these would not be paying a node-recognized address. (Litecoin/EVM/Monero are correct and show the right pattern.)
4. MAJOR wiring gaps (P1 — real logic, no runtime consumer / persistence)#
These do not fabricate, but the feature is non-functional end-to-end until wired.
- No persistence anywhere it matters. The admin BFF
(
apps/oshun/bff/src/admin/state.ts, 30,824 lines) is an in-memoryMapwithreset()+ fixture seeders — every governance action is non-durable and per-instance. Living Scenes, Trust-Safety, Iris, Studio, Tenant-admin surfaces are likewise in-memory or pure-functional. Onlydomain-stubs-postgres.ts(tara completions, telegram links, SCIM CRUD) and the Prisma layer are DB-backed. - Customer domain adapters point at non-existent contract routes. The BFF's
real HTTP adapter calls
/v1/oshun/*; the standalone domain APIs (apps/tara/api, …) serve a different namespace and implement zero/v1/oshun/*routes → 503 in prod. So the honest path serves nothing and the populated path is fixtures. - No idempotency middleware in the BFF. ARCH §1064-1108 mandates idempotency as the first step of every write; it does not exist (0 non-test hits). Rate-limiting is in-memory (non-distributed). (Idempotency fixed in this pass — see §8; distributed rate-limiting still pending.)
- Lilith crisis classifier not wired to its adapter.
canonical-adapter.tsassessSafetydepends on an injectedapiAdapter.analyzeSafetywith no concrete implementation; the validated 13-rule crisis catalog (detectLilithCrises) is unreachable from the adapter path. (Fixed in this pass — see §8.) - Isis generation control has zero importers. No BFF route, no admin app,
no tsconfig alias routes through
dispatchGeneration/routeApprovedOshunMediaGenerationRequest. The "Isis is the only path; raw provider machinery is never customer-facing" guarantee cannot hold until a surface routes through it. - Agentic-Studio enforcement decides but never acts. No orchestrator
consumes
decideExecution/checkBudget/acquireToken; the run state machine has nokilledstatus; no automatic budget/kill-switch → run-termination path. Exit criterion ("budgets honored, kill switches enforced") not met end-to-end. (Fixed in this pass — see §8.) - Studio findings→gate loop is open.
block-severityAuthoringEvaluationFindings are not folded intoEditorialGate.satisfied; gate satisfaction is caller-supplied, so blocking findings don't actually block publish. (Fixed in this pass — see §8.) - Iris has no concrete persistence adapter.
IrisMemoryApiAdapteris an unimplemented interface;createCanonicalIrisMemoryAdapterhas zero production callers. Privacy guarantees are correct in code but not enforced against real data. DSAR export only covers scene/pose scopes. - Trust-Safety crisis-frame cascade is absent.
crisis/crisis.tsdoes single-domain routing/records but never publisheslilith.crisis_frame.activatedor projects the frame into Tara/Living-Scenes/Isis/Assistant/Iris. The cross-surface cascade (ARCH §1692-1740) does not exist. - Metis runtime disconnect. The api-gateway/web proxy to an out-of-repo
Python backend; the real TS grading/IRT/mastery/adaptive logic in
libs/metis/*is not imported by any in-repo runtime; the adaptive loop is never instantiated with production runners. The unified 7-gate release pipeline does not exist (4 of 7 enforce in scattered places; grounding/pedagogy/drift are helpers only). - Billing-Support is an island. No imports of Aje/payment adapter; not consumed by any app; a second, parallel entitlement model lives in auth-client.
- Tenant Console: forgeable session + missing protocols. Unsigned base64 session cookie defeats tenant isolation in prod; LTI 1.3/LTI Advantage/SCORM absent; SAML/OIDC signature verification assumed-upstream (not located in-subsystem).
- Admin missing workflow areas. Trust&Safety (no moderation/appeal/crisis actions — read-only + copilot-feedback only), Support/Billing/Entitlements (no refund/credit/grant/case-resolution), and Metis governance (no surface) fail the "operate ALL workflows" exit criterion.
- Messaging delivery transports. Only Telegram actually sends; Email/Push/SMS/WhatsApp are payload/plan builders with no wired SES/Twilio/FCM/APNs/Meta client; Discord/Slack are gating-only; bot voice STT is a placeholder.
5. MINOR (P2 — cleanups, latent footguns)#
@veritas/contractsbroken tsconfig path → empty.gitkeep-only dir; dangling alias (zero importers today). Removal deferred:tsconfig.base.jsonis a global Nx dependency, so editing it forces an affected-typecheck across the entire monorepo, which currently fails on unrelated pre-existing WIP package errors. Remove it in a dedicated cleanup commit once the repo-wide typecheck is green.@noble/hashesversion skew —payments-bridgecold-spend-queue imports@noble/hashes/sha256(dropped in v2.2.0); breaks telegram-bot test loading. (Fixed in this pass — see §8.)- Veritas
bandFromCompositeredundant'low'branch (banding threshold dead); disagreement substring heuristic on free-textrationale. - Isis
admitCivitaiImportedModelAtRuntimedoesn't implement its documented customer-facing check (defense-in-depth only; the binding check is upstream). - Tara: 4-week-only practice-plan continuation; vestigial crisis-type branch; static recommendation table.
- Shell-wearable:
buildAchievementProgressComplication/buildChallengeProgressComplicationreturnvalue:0(no source fields inWearableUserStats). - Yemaya/Living-Scenes contract
RenderEnvelopeSchemadiverges from the runtime envelope (missing reproducibility fields). - Billing-Support: unused
nowUnixSecondsparam + deadpast-period-enderror code. - Telegram bot: prod token silently defaults to literal
'prod-token'when env unset (should fail-fast). (Fixed in this pass — see §8.) - Analytics: 14.5k LOC of out-of-V1-scope V3 game-engine gates inflate the package.
6. What IS production-grade (credit where due)#
Not everything is a gap. The following are genuinely real, domain-specific, and well-tested — they should be trusted and not re-litigated:
- Tara, Arete, Nisaba domain logic + contracts (Nisaba's in-repo morphology across 9 ancient languages, concept graph, and lexicon are exceptional).
- Search & Discovery (real BM25/cosine/NDCG/MAP, deterministic FNV-1a A/B bucketing, 123/123 coherent tests).
- Sophia evidence/transform layer; Psyche policy/contract layer; Persona Registry (1422 tests); Themis academic-integrity adjudication.
- Consumer Shell (all 6 libs; real ordering/NLU/Iris bridge; 1563 tests).
- Auth (real alg-pinned signed-JWT verification, RBAC denials, no bypass, no hardcoded secrets).
- Foundations: domain-registry matches the spec table; 85-model Prisma
schema with real migrations and contract-drift enforcement;
libs/shared/*substrates (idempotency 692 LOC, durable queue + DLQ, event-bus with HMAC signing, residency enforcer, audit-platform) are real. - Aje payments money path: real per-asset confirmation ladder, real RPC confirmation reads, Ed25519 receipt signing, non-custodial watch-only invariants; Litecoin/EVM/Monero address derivation is correct.
- Lilith / Persona safety algorithms (crisis classifier, voice-abuse scoring, impersonation detection); Isis gate-enforcement core; Agentic-Studio governance primitives — all real, just unwired.
7. Prioritized Remediation Roadmap#
Phase 0 — Stop shipping harmful fabrications (days). Make the dangerous BFF
fixtures fail honestly (dead crypto address, consent/memory state, operator
audit/SSO/incidents) → 503/not-configured rather than fabricate; gate the web
fabricate-on-failure paths behind an explicit "data unavailable" state instead
of silently rendering invented sky/news data. (Partially addressed in §8.)
Phase 1 — Persistence + BFF data plane (weeks). Stand up real datastores
behind the admin BFF and the domain stub routes; implement the contracted
/v1/oshun/* backend routes (or repoint adapters at the real domain-API
namespace); add idempotency middleware and distributed rate-limiting. This
unblocks the majority of "real logic, no consumer" gaps at once.
Phase 2 — Wire the governance decision planes to runtime (weeks). Build the
orchestrators that consume the already-correct decision functions:
Agentic-Studio executor (budget/kill-switch → run termination), Isis dispatch
surface, Studio findings→gate binding + publish enforcement, Iris concrete
persistence adapter, Lilith default analyzeSafety (done — §8), Trust-Safety
queue/audit wiring + the cross-surface crisis-frame cascade, Billing-Support ↔
Aje integration.
Phase 3 — Build the genuine missing engines (weeks-months, specialist). Privacy DSAR/deletion that actually deletes + fans tombstones across domains with cryptographic shred; Yemaya render kernel (Rust/wgpu per CLAUDE.md) + Living-Scenes render/blend/determinism/watermark-embed/real-C2PA-signing; Metis 7-gate release pipeline + in-repo runtime (or import the Python backend into scope); replace Metis worker seeded-RNG fakes with real aggregation; replace research-agent source fabrication with real retrieval; chain-valid address derivation for Tron/TON/Ergo/Cardano; analytics aggregation + offline-eval runners.
Phase 4 — Surface completeness & hardening (weeks). Admin Trust&Safety/Support/Metis-governance mutation surfaces; Tenant-Console signed sessions + LTI/SCORM; messaging Email/Push/SMS/WhatsApp transports + bot STT; Nyx ephemeris service + power-user pages.
8. Fixes applied in this audit pass#
Targeted, self-contained, verified fixes (the bulk of the roadmap is multi-team and out of a single session's scope):
-
Lilith crisis classifier wired into the adapter (safety-critical). A default
analyzeSafetynow routes through the validateddetectLilithCrisescatalog so the per-turn adapter path inherits real crisis detection instead of depending on an unimplemented injected dependency. -
@noble/hashesimport skew fixed inpayments-bridgecold-spend-queue (/sha256→/sha2.js), unblocking telegram-bot test loading (catalog pins^2.2.0, which dropped the/sha256subpath). -
BFF crypto-quote route fails closed —
POST /v1/payments/crypto/quotenow returns503 payments_not_configuredand issues no receiving address, instead of handing the customer a burn address (0x…dead). -
Dangerous BFF read fixtures fail closed in production — the fixtures that shipped fabricated privacy (
/v1/data-rights/consent,/v1/memory), operator-integrity (/v1/audit,/v1/sso,/v1/incidents), and misinformation (/v1/veritas/retractions,/v1/sophia/grounded|answer,/v1/nyx/tonight) data with200 OKnow return503 not_configuredwhenNODE_ENV/OSHUN_ENV/RUNTIME_ENV === production(viaguardedFixtureRoute/blockFixtureInProduction). Dev/test still serve the fixtures, so demos and the existing fixture-shape test are unaffected; a new test asserts the prod-503 behavior (domain-stubs-route 65/65 green). Production never ships fabricated consent/audit/SSO/incident/grounding/sky data to real users or operators. -
Web
nyx/tonightno longer fabricates astronomy on backend failure —apps/oshun/web/src/lib/server/nyx-depth.tsreturned invented sky events (a specific "Jupiter conjunct the waxing moon" with exact times) whenever the BFF was unreachable; since the BFF now fails closed in prod, that fallback would re-introduce fabricated astronomy. It now returns an honest "data unavailable" state (empty events + explanatory headline); the page renders the headline and no fabricated lead event. (The home Veritas-briefing fallback is left as-is — it carries a deliberate "Curated briefing" disclosure pill and dedicated tests, so that one is the owner's UX call.) -
Metis worker analytics no longer fabricates metrics — the registered
AnalyticsAggregateProcessor/AnalyticsSnapshotProcessor(apps/metis/worker) computed every metric from a seeded RNG. They now read from an injectable realMetisAnalyticsDataSourceand fail closed (success:false, "no analytics data source configured") when none is wired, instead of inventing engagement/performance/retention/content/snapshot numbers. The real statistical machinery (time-series bucketing, percentiles, trend regression) is preserved and now operates on real data; tests rewritten to the data-source + fail-closed paths. -
Metis worker reports no longer fabricate data — the registered
ReportProcessorbuilt learner-progress / course-analytics / engagement reports from seeded-RNGcollect*Datamethods. It now reads from an injectableMetisReportDataSourceand fails closed when none is wired, with the real report/chart/CSV/PDF/JSON formatting machinery preserved. (analytics 40, reports 87; full metis/worker suite 735/735 green.) Also fixed the worker's empty-includetsconfig.jsonso typed linting/typecheck actually cover its sources. -
Metis worker notifications no longer fabricate delivery success — the registered
NotificationProcessor/BatchNotificationProcessorformatted email/push/SMS/in-app messages, thenvoid-discarded them and returneddelivered:true. They now hand the formatted message to an injectableNotificationDeliveryTransportand reportdelivered:falsewhen none is configured — never a fabricated success that would mask real delivery failures. (notification 80; full metis/worker suite 737/737 green.) -
Metis worker course-export no longer fabricates course content — the registered
CourseExportProcessorsynthesized modules/lessons/media/ assessments from a hash of the courseId and exported that invented content. It now loads from an injectableMetisCourseLoaderand fails closed (or "course not found") when none is wired, with the real PDF/SCORM/HTML/EPUB/JSON export + manifest machinery preserved. The deterministic generation moved into the test as a fake loader. (course-export 96; full metis/worker suite 740/740 green.) With this, the Metis worker contains no fabricated-code paths — analytics, reports, notifications, and exports all ground-or-fail-closed. -
Metis research-agent no longer fabricates sources —
ResearchAgent(libs/metis/agents) now retrieves from an injectable realResearchSourceRetrieverand abstains (metadata.grounded:false, empty result, explanatory summary) when none is configured, instead of manufacturing fake sources with invented relevance/reliability scores. Removes theMath.random/Author A/B/Cstub that directly violated the fabricated-research-blocking requirement; spec rewritten to test the grounded retriever path and the abstention path (18 tests; full lib 876/876 green). -
@veritas/contractsdangling tsconfig alias — removal deferred to a dedicated cleanup commit (see §5): editingtsconfig.base.jsontriggers a repo-wide affected-typecheck that currently fails on unrelated pre-existing WIP errors. -
Runtime persistence layer built (T1 Step 1) —
@oshun/persistencehad no Prisma-client-backed repository (only the build-time schema spec). Added a generic, projection-drivenContractRecordRepository(put/get/tombstone +computeContractPayloadHash+prismaDelegateResolver) that serves all 85 models without drift. Type-clean under the lib's real typecheck; 10 unit tests- full persistence suite green. This is the foundation the Iris/admin/Veritas durability work (T1 Step 2, T2, T4) layers on. See §10 T1.
-
T1 hardening — two real defects found by widening real-DB verification, then fixed. Extending the integration test from the scalar-only
DurationBuckettotara:SittingCompletionEvent(a contract with atimestamptzcolumn,completedAt, and ajsonbcolumn,timestamps) surfaced two genuine bugs the original round-trip could not have caught:- The committed Prisma client was stale (77 of 85 models). The last three
feature commits added 8 contracts to the registry + schema + migrations but
never regenerated the tracked client (
src/generated/client), and the renderer emitted a Prisma-6 generator block (prisma-client-js→node_modules/.prisma/client) inconsistent with the Prisma-7 TS client that actually ships — so the regen pipeline never refreshed it. Net effect:ContractPersistenceService.put('tara','SittingCompletionEvent',…)(and 7 other registered contracts) threwno Prisma delegateat runtime — those contracts were unpersistable as shipped. Fixed at the source:prisma-renderer.tsnow emits the correct Prisma-7 block (prisma-client→../src/generated/client,importFileExtension = ""); regenerating yields all 85 models with the existing 77 byte-identical (purely additive). deserializesilently dropped contract fields that share a name with the control envelope. It skipped any projected field in aCONTROL_COLUMN_SET(tenantId,sourceRecordId, …) — but those projections are contract-declared fields, and many V1 contracts carry their owntenantId(SittingCompletionEvent, MessagingAccountLink, …). On read the field came backundefinedand re-validation failed. Fixed: every projected field is a contract field and is rehydrated (envelope-only columns are never in the Zod schema, so they still never leak);putnow throws if a contract-declaredtenantId/sourceRecordId/etc. disagrees with the stamped envelope value (no silent overwrite). Covered by 2 new unit tests + the real-PostgresSittingCompletionEventround-trip (timestamptz + jsonb + own-tenantId).
- The committed Prisma client was stale (77 of 85 models). The last three
feature commits added 8 contracts to the registry + schema + migrations but
never regenerated the tracked client (
-
Veritas retraction cascade — emitter half built (T2, in-repo side). The audit flagged the cascade as an in-memory planner that "never cascades": it computed which stories/claims/explainers/evidence-packs/downstream Metis lessons to re-ground or re-validate, but nothing persisted or dispatched the plan. Added
executeVeritasSourceRetractionCascade(domain-veritas/src/ retraction-cascade-execution.ts): it runs the existing planner, persists theRetractionCascade(a registered envelope contract — id-keyed, no revision chain — so it round-trips through the contract repository directly), then publishes averitas.retraction.cascade.dispatchedevent carrying the per-target re-grounding/re-validation jobs. Persist strictly precedes publish (fail-closed: a crash between them never dispatches a non-durable cascade). Depends only on small injected ports (RetractionCascadePersistence/RetractionCascadeEvent), sodomain-veritasstays infra-free; the app boundary suppliesContractPersistenceService.put('veritas','RetractionCascade',…)andIEventBus.publish. 2 unit tests (plan→persist→publish ordering; no dispatch when persistence fails) + full domain-veritas suite green (304). Remaining (out of repo / infra): the Sophia re-grounding and Metis lesson re-validation consumers, and registering the topic in the event-busDEFAULT_EVENT_TOPIC_DEFINITIONSfor enforced-mode schema stamping. -
Veritas story-update notifications — dispatch built (emitter). A smaller parallel to the cascade:
resolveVeritasStoryUpdateNotificationsalready did real per-recipient resolution (topic match, preference/mute/frequency suppression, modality selection, dedup) but itsdeliverieswere never emitted — followers were never actually notified. AddeddispatchVeritasStoryUpdateNotifications(story-update-notification-dispatch.ts): run the resolver, publish oneveritas.story-update.notification.dispatchedevent per delivery (keyed by the deterministicnotificationIdfor idempotency); suppressed candidates are never emitted. Publish-only by design (a notification is a transient delivery, not a durable entity). 2 unit tests (only deliveries emitted; nothing emitted when all suppressed) + suite green (306). The push/email/in-app transports remain out-of-repo consumers. -
Telegram bot prod token — fail-closed (P2 safety). The prod environment silently defaulted its bot token to the literal
'prod-token'whenOSHUN_TELEGRAM_BOT_TOKEN_PRODwas unset, so a misconfigured production deploy would authenticate with a fake token instead of erroring.createOshunGrammyBotnow throws forprodwhen the token is the unconfigured-placeholder sentinel (dev/staging keep their convenience placeholders). 1 new unit test + suite green (14); typecheck clean. -
Iris durable memory persistence built (the substrate's #1 gap). The §10.8
MemoryStorewas in-memory only — a restart lost every memory. Added a durable, revision-chained store. Because aMemoryEntrydoes not fit the contract-envelope foundation (keyed perrevisionIdnot a stableid; nullable domaintenantIdthat would collide with the non-null envelope partition; user-scoped not tenant-scoped), it persists to a bespokeiris_memory_entry_revisiontable (added via a newrenderBespokeModels()chunk inprisma-renderer.ts, so the one generated-schema/migration/client pipeline still covers it): one row per revision, the full validatedMemoryEntryas a JSONpayload,entryId/userId/lifecycleprojected out, and a partial unique index (entry_id WHERE lifecycle <> 'superseded', in the migration) enforcing exactly one current revision per entry.DurableMemoryStore(durable-memory-store.ts) mirrors the in-memory API (create/update/tombstone/recordReference/getLatest/getRevision/history/list/ summarize) async, doing supersede-then-insert inside an interactive$transaction. The DSAR-vs-immutability tension is resolved:tombstonestays terminal-but-body-retaining (immutable audit, per §10.8), and a newforgetdoes a true hard-purge of every revision for right-to-be-forgotten. 7 unit tests + a real-Postgres integration test (create→update→supersede→ tombstone→forget, partial-unique verified) — both green; lib typecheck clean. -
Nyx real ephemeris built (replaces fabricated sky data). There was no in-repo astronomical computation —
nyx/tonightwas fixtured and the web layer fabricated sky data on failure. Addeddomain-nyx/src/ephemeris.ts: real geocentric computation from the standard Meeus algorithms — Julian Day (ch.7), solar apparent position (ch.25), lunar position via the principal periodic terms (ch.47), and lunar illuminated fraction / phase (ch.48) — plus acomputeNightSky(date)summary. 16 known-answer tests pin every routine to Meeus's published worked examples (JD = 2451545.0 at J2000; Sun ex 25.b; Moon ex 47.a to arc-minutes; illumination ex 48.a; known new/full-moon dates), so a coefficient-transcription error fails loudly. Full Nyx suite 200 green; typecheck clean. Follow-up: rise/set/transit + horizontal coords + wiringnyx/tonightto consume it, and the 19 power-user pages. -
Living Scenes provenance — real C2PA signing + real watermark DSP. Two of the three §25.4 fabrications fixed. (1) The C2PA sidecar took injected
sign/verifywired to a faked signature; addedcreateEd25519C2paSigner/createEd25519C2paVerifier(provenance/c2pa/ed25519-signer.ts) over@noble/curvesEd25519, so a manifest carries a genuine 64-byte signature bound to the key and tamper-evident. (2) The watermark module only encoded a payload + scored a recovered chip stream — the actual embed/extract was "absent"; addedprovenance/audio-watermark/dsp.ts: real spread-spectrumembedWatermark/extractWatermark(each ±1 chip spread by a deterministic PN sequence, recovered by correlation). 10 tests: sign→verify round-trip + tamper- wrong-key rejection; watermark embed→extract survives a round-trip and moderate additive noise, and a wrong PN key recovers nothing. Full living-scenes-runtime suite green; typecheck clean.
-
Living Scenes takedown — now actually mutates. The
apply*dispositions computed aDispositionImpact(new playback state, share-link state) and the nightly audit checked an SLA against acascadedAtUnixSecondsthat nothing produced — the "cascade mutates nothing" finding. Addedtakedown/execution.ts:executeTakedownDisposition/executeTakedownCascadeapply the prescribed mutations (set artifact playback + each public share-link state) through an injectedTakedownArtifactMutator, stampcascadedAtUnixSeconds, and return records that feedauditNightlyCascade. Fail-closed: a mutation that throws leavescascadedAtUnixSecondsnull (an SLA miss), never a silent success. 3 tests (real mutation + SLA-met; fail-closed + SLA-missed; batch cascade); full living-scenes-runtime suite 220 green; typecheck clean. Remaining §25.4: the GPU render/blend kernel (a separate engine effort). -
Metis release-gate pipeline now exists (fail-closed orchestrator). The audit found the named "7 release gates" had per-gate decision logic scattered across the Metis libs but no pipeline running them as one release decision. Added
release-pipeline.ts(@metis/course/validation):evaluateReleaseGatesruns a set of namedReleaseGates and is release-ready only if every required gate is present and PASSED — a gate that FAILS, is SKIPPED, throws, or is absent blocks the release (never a silent pass).METIS_RELEASE_GATESnames the canonical seven;courseQualityReleaseGateswires the three real course-quality gates (structure/textbook/presentation) against their existing implementations. 7 tests (pass/fail/skip/throw/missing-required + real-gate wiring); full@metis/coursesuite 586 green; typecheck clean. Follow-up: register the remaining four gates asReleaseGateadapters over the existing source-grounding / assessment-validity / academic-integrity / accessibility decision functions (heterogeneous inputs). (The worker seeded-RNG fakes and the research-agent source fabrication were already fixed earlier this audit.) -
Isis gate now reachable + a fail-closed dispatch guard. The release-gate logic was real and tested but the lib (
@oshun/generation-control-isis) had notsconfig.base.jsonpath alias — literally unimportable by name, hence "zero importers, not wired." Added the alias (+/*), so the gate is now reachable, and addeddispatch-guard.ts:evaluateIsisDispatchis the canonical enforcement seam a surface calls before releasing a generation — it runs the realevaluateReleaseGateand permits dispatch ONLY on an explicitallowwith every runtime admission admitted; ablock/reviewverdict, a gate error, or a denied admission all DENY (fail-closed). 5 tests (allow/block/review + denied-admission + all-admitted); full isis suite 401 green; lib typecheck clean. Remaining (Isis): wire the seam into the out-of-repo generation runtime, and the still-absent tier-resolver / surface-guard / LoRA-training features. -
Privacy DSAR — real erasure cascade (replaces soft-flag-only). The deletion path marked a request but never erased the subject's data (a contract-envelope
tombstonekeeps the payload columns — an audit marker, not erasure). Added a true-erasure primitivepurge(contract, identity)toContractRecordRepository+ContractPersistenceService(hard-deletes the row), andexecuteDsarDeletionCascade(dsar-deletion-cascade.ts): it purges the subject's contract records andforgets their Iris memory, emitting a verifiableDsarDeletionReceipt. Fail-closed:completeonly if every target was erased or already absent — any failure (or a memory target with no eraser configured) leaves the DSAR unsatisfied. The per-domain subject→records enumeration is the caller's injected boundary. 4 unit tests + a real-Postgres integration test proving the row is truly gone (not tombstoned) and a re-run is satisfied via not-found. Full persistence suite green; typecheck clean. -
Nyx ephemeris — observer geometry + rise/set (completes the core). Extended
ephemeris.tswithgreenwichMeanSiderealTime,localSiderealTime,equatorialToHorizontal(alt/az),riseTransitSet(rise/transit/set with circumpolar / never-rises handling), and a location-awarecomputeTonight(moon phase + where the Sun/Moon are now + their rise/set). Verified against Meeus's worked examples (GMST ex 12.a; horizontal ex 13.b — Venus alt/az) plus a rigorous self-consistency check (a fixed body sits exactly at its standard altitude at the computed rise/set — which surfaced and fixed a sidereal-rate bug: events must solve GMST mod 360 at the 360.98565°/day sidereal rate, not by wrapping solar-day fractions). Full domain-nyx suite 205 green; typecheck clean. Remaining (Nyx): wirenyx/tonightto consumecomputeTonightinstead of the fixture, and the 19 power-user pages. -
Metis 7-gate pipeline — all four remaining gates now wired. Completed the gate set:
gateFromValidationResultadapts any@metis/linters-typesValidationResult(structurally, no cross-lib dep) into aReleaseGate— fail-closed (pass→passed,skipped→skipped/blocking, fail/warning/error→ blocked with the issue messages), covering accessibility, assessment-validity, and source-grounding (fact-check);metisReleaseGates(...)assembles the full seven (3 course-quality + those 3 validation gates + a caller-supplied academic-integrity gate, whose result shape differs). 6 new tests; full@metis/coursesuite 592 green; typecheck clean. The named "7 release gates" now exist as one fail-closed pipeline with every gate wired to real logic. -
Admin durability — typed durable store built (the store the admin adopts). The admin BFF kept records in in-memory
Maps. Their canonical contracts (Incident, SupportCase, ReviewPackage, Tenant, PolicyBundle, Persona) turned out to be already modelled ascross-cuttingcontracts, so durability is achievable through the foundation today — what was missing was a typed store. Addedadmin-record-persistence.ts: a generic, reusabletypedContractStore<T>overContractPersistenceService(put/get/list/tombstone/purge, inheriting the envelope/validation/tombstone semantics) andcreateAdminRecordPersistenceexposing each admin record class typed to its contract. 2 tests (routing for every class → its cross-cutting contract; generic reuse). Lib typecheck clean. Remaining for #11: the admin BFF adopting it in place of the in-memoryMaps — a careful rewiring of the 30k-lineadmin/state.ts(integration, not new capability) plus the design call of canonical-contract vs admin view-DTO. -
TRON real on-chain address derivation (the money-critical fabrication). Per-invoice deposit addresses were synthetic (
T${sha256(seed||index).slice}) — not chain-valid, so java-tron'svalidateaddresswould reject them and break invoicing. Addedtron-address.ts:tronAddressFromPublicKeyimplements the real scheme (secp256k1 pubkey → keccak256(X‖Y) last-20 →0x41prefix → base58check) +decodeTronAddress/isValidTronAddress. RedesignedTronAllocatorto watch-only: it now takes an account xpub (not a seed) and derives per-invoice addresses as non-hardened BIP32 public children via@scure/bip32— spending keys never enter the process; it rejects an xprv. Verified WITHOUT external fetches: the derivation reproduces the canonical secp256k1priv=1account id (Ethereum's0x7E5F…Bdf) and every address base58check-round-trips to0x41‖id. Full@aje/chains-tronsuite 34 green; typecheck clean. -
Ergo real P2PK address derivation. Per-invoice addresses were synthetic (
9${sha256(seed||index).slice(0,50)}— bare hex, not even base58). Addedergo-address.ts:ergoP2pkAddressFromPublicKeyimplements the real sigmastate scheme (head bytenetwork+P2PK‖ 33-byte compressed secp256k1 key ‖blake2b-256(head‖key)[0..4]checksum, base58-encoded) +decodeErgoAddress/isValidErgoAddress. RedesignedErgoP2pkAllocatorto the same watch-only xpub + non-hardened-child model as TRON (m/44'/429'/0'/0/<i>). Verified against five canonical sigmastate/fleet-sdk(public key → mainnet address)vectors (e.g.038d39af…a58a63→9hY16vzHmmfyVBwKeFGHvb2bMFsG94A1u7To1QWtUokACyFVENQ), plus checksum-tamper rejection and compressed/uncompressed equivalence. Full@aje/chains-ergosuite 29 green; typecheck clean. -
TON real v4r2 address derivation. The per-invoice account id was synthetic — a
sha256(publicKey‖walletId‖subwalletId)digest wrapped in the (real) friendly-address envelope, so funds sent there were unsweepable. A TON address isworkchain:sha256(StateInit cell); rewrotesubwallet.tsto build the genuine v4r2 StateInit ({code, data}with the canonical v4r2 code cell +seqno‖subwallet_id‖pubkey‖∅data) and hash it with@ton/core— the same cell hashing the operator's own cold-spend tooling and every TON wallet/explorer use, so the address is sweepable by construction. The code cell loads from the canonical BoC (Cell.fromBocverifies its CRC32C, so a transcription error throws). Per-invoice distinct addresses come from a monotonicsubwallet_idoffset; the allocator stays watch-only (public key only). Verified by an in-suite oracle test asserting the derivation is byte-identical to@ton/ton's referenceWalletContractV4across four keys × two workchains, plus a documented snapshot vector (EQDgICpEIOY6eV348OIAf8Q-spcHAt0C2qi5A4MPKP2y773N). Full@aje/chains-tonsuite 40 green; typecheck clean. -
Cardano real CIP-19 address derivation. Per-invoice addresses were synthetic (
addr1_${sha256(seed||index).slice(0,40)}— not even bech32), so any Cardano node/wallet would reject them. Addedcardano-address.ts:cardanoBaseAddress/cardanoEnterpriseAddressbuild genuine CIP-19 addresses (header(type‖network) ‖ blake2b-224(payment key) [‖ blake2b-224(stake key)], bech32 with Cardano's relaxed length limit) +decodeCardanoAddress/isValidCardanoAddress. RedesignedCip1852Allocatorto watch-only: it takes the Ed25519-BIP32 account xpub (rejects a 96-byte xprv) and derives per-invoice payment credentials as non-hardened public children…/0/<i>with a fixed staking credential…/2/0, via@stricahq/bip32ed25519(the canonical pure-TS Ed25519-BIP32). Verified two ways: (a) the address encoding reproduces the CIP-19 published test vectors (type-00 base + type-06 enterprise, mainnet + testnet) byte-for-byte, and (b) a derivation-consistency test proves the watch-only public-derived key equals the private-key path the operator spends with (so deposits are sweepable), across both chains and several indices. Full@aje/chains-cardanosuite 27 green; typecheck clean. -
#13 complete: all four non-EVM rails (TRON, Ergo, TON, Cardano) now derive real, chain-valid, watch-only deposit addresses, each verified against authoritative per-chain vectors/oracles.
-
Isis civitai intake — sha256 hex validation.
evaluateIntakeCandidatechecked the digest's length but not its alphabet, so a 64-char non-hex string was admitted to staging despite the "64 hex chars" contract. Tightened to/^[0-9a-f]{64}$/iwith a test. -
Yemaya raster render/blend kernel (the "simulated rendering, no pixels" fabrication).
RenderCore.executeJobcomputed estimated metrics with no pixels, and the visual-compositor'sapplyBlurdampened contrast on a single colour (a blur is a spatial operation — impossible on one colour). Addedraster-kernel.ts, a real CPU reference renderer over RGBA8 buffers:compositeOver(W3C Compositing-and-Blending source-over reusing the existing real separable blend-mode functions),gaussianBlur(a genuine separable Gaussian — 1-D kernel from σ, two passes, edge-clamped, premultiplied-alpha so transparent edges don't darken),vignette(radial darkening by true pixel distance), andrenderLayerStack(bottom-to-top multi-layer compositing). Verified by 17 known-answer tests: multiply(red,blue)=black, screen=magenta, 50%-over-midpoint, transparent-source is a no-op; blur conserves energy (float-exact, ~8% 8-bit quantization loss), is symmetric/isotropic, and keeps a white-on-transparent edge pure white; vignette leaves the centre untouched and halves the corner at amount 0.5. Full@yemaya/rendering-pipelinessuite green; typecheck clean. -
Yemaya composition renderer (consuming the kernel — real pixels from the scene model). Added
rasterizeComposition(Composition): it composites the composition's visible layers in ascendingorderoverbackgroundColor, each with its blend mode + opacity, producing an actual RGBA8 image. Solid-fill (shape) layers are placed with full affine fidelity —positionis the anchor point,scalestretchesdimensions, androtationis applied exactly via an inverse point-in-rect test (FP-boundary-robust). The fill colour is read fromcontent.data.fill/.color;image/text/groupcontent is skipped, not fabricated (a bitmap decoder / text shaper / group flattener are separate engines) and counted inskippedLayerCount. 9 known-answer tests: anchor-aware placement, exact 90° rotation (4×2 → 2×4), scale, multiply/opacity blend over the background, layer-order precedence, invisible/zero-opacity skipping, and honest bitmap/text skipping. Full@yemaya/rendering-pipelinessuite 1532 green; typecheck clean. -
Yemaya real render path on the orchestrator.
RenderCore.executeJobwas the audit's flagged "simulates rendering + fabricated frame/memory/FPS telemetry, no pixels." AddedRenderCore.renderComposition(composition): it drives the kernel'srasterizeCompositionto produce an actual RGBA8 image and returns measured metrics — real wall-clock duration, the true output-buffer byte size, the count of layers that actually contributed, and skipped non-solid layers surfaced as warnings — emittingjobCompleted/metricsCollectedand recording history.executeJobis retained and re-labelled as what it is: a deterministic cost planner (estimates, no pixels), distinct from the real render path. 3 tests assert real pixels + measured (not estimated) metrics + event emission. Full@yemaya/rendering-pipelinessuite 1535 green; typecheck clean. -
Yemaya anti-aliased rotated edges.
rasterizeSolidLayersampled one point at each pixel centre, so rotated/diagonal layer edges were jagged. Added coverage supersampling (antialiasSamplesper axis, default 4 → 16 sub-samples/pixel): an edge pixel's alpha isfillAlpha × coverage, so rotated edges get smooth fractional alpha while fully-inside pixels stay opaque and fully-outside transparent. Axis-aligned edges on integer boundaries stay crisp at any setting (no sub-sample straddles them), so all prior known-answer tests are unchanged. Verified by a 45° diamond test (fractional-alpha edge pixels exist with AA on; only 0/255 withantialiasSamples: 1). Full@yemaya/rendering-pipelinessuite 1536 green; typecheck clean. -
Yemaya per-layer effect pass. Added
applyLayerEffects(image, effects), wired into the composition pass: each layer'seffectsare applied to its buffer in ascendingorderwith real math — blur (the kernel's separable Gaussian), vignette, brightness, contrast, saturation (the compositor's existing colour formulas), grayscale (Rec.709 luminance), invert, the standard sepia matrix, hue-rotate (HSL rotation), and a 3×3 sharpen convolution (DC-preserving, premultiplied, edge-clamped). Effects that need extra buffers (shadow, glow) or other engines (masks, gradients, …) are returned inunsupportedrather than faked. 13 known-answer tests (invert red→cyan, greyscale red→54, sepia white→(255,255,239), brightness +0.5→+128, hue-rotate red→green@120°/blue@240°, blur-effect == direct gaussianBlur, sharpen DC-preserving + peak overshoot, ordered application, disabled-skip, unsupported-list, no-mutation). Full@yemaya/rendering-pipelinessuite 1549 green; typecheck clean. -
Yemaya shadow/glow effects + mask primitives. Added drop-shadow (tint silhouette → offset → blur → composite content over it) and outer glow (tint → blur → intensity → composite over) to the effect pass, with a documented numeric param contract (
r/g/b/a,offsetX/offsetY,blur,intensity), plustintImage/translateImagehelpers. Exposed realapplyAlphaMaskandapplyLuminanceMaskkernel primitives (multiply image alpha by the mask's alpha / Rec.709 luminance). The effect pass now covers 12 effects; onlyMask(needs a mask source theEffectdoesn't carry — callers use the primitives directly), gradients, borders, noise, etc. remain inunsupported. 5 new known-answer tests (offset shadow lands behind content; red glow halo is red-dominant with falloff; alpha-mask hides the masked half; luminance-mask maps grey→128 alpha; dimension-mismatch throws). Full@yemaya/rendering-pipelinessuite 1554 green; typecheck clean. Remaining for Yemaya: GPU/wgpu acceleration and image/text-layer engines (bitmap decode + text shaping). -
Durable admin audit-events store (#11 — compliance slice). The operator audit log (
apps/oshun/bff/src/admin/admin-audit-events-store.ts) was an in-memory ring buffer — a process restart erased the operator audit trail, a compliance gap. BuiltDurableAdminAuditEventsStoreon the persistence foundation, exactly mirroring the Iris durable-store pattern: a bespokeadmin_audit_eventtable (added torenderBespokeModels, regenerated schema + client, new migration), append-only and operator-scoped, withoccurredAt/eventTypeprojected for the per-operator recency list, the relevance-ranked universal-search facet (scoring identical to the in-memory store), the §19.1 cross-operator explorer (actor / workspace / type-prefix / time-window / free-text filters),readEvent,size, andpurgeActor(DSAR hard erasure of one operator's trail). 6 unit tests (fake delegate, all logic) + a live-Postgres integration test (persist/read/list/search/cross-query/time-window/purge) — both green;@oshun/persistenceunit suite 51 green; typecheck clean. This durable slice + the existingcreateAdminRecordPersistencetyped contract stores (Incident/SupportCase/ReviewPackage/Tenant/PolicyBundle/Persona) are the durable substrates the admin surface adopts; the remaining #11 work is the large mechanical rewire of the 30k-line in-memorystate.tsonto them. -
Write-through durable adapter for the BFF audit log (#11 — the glue). The BFF injects a SYNC
AdminAuditEventsStore(options.auditEventsStore) at ~50 call sites; the durable store is async. AddedcreateDurableBackedAuditEventsStore(apps/oshun/bff/src/admin/): it wraps the in-memory ring buffer (unchanged sync reads + syncrecordreturning the event) and additionally writes each event through to an injected durable sink (DurableAuditSinkport — the BFF takes no@oshun/persistencedependency; the app entry adapts the realDurableAdminAuditEventsStore), plushydrate()to reload the recent trail into the cache on startup. Write-through is at-least-once fire-and-forget (the sync interface can't await) with failures surfaced viaonError, not swallowed — strictly better than the prior lose-everything-on-restart. Added aseed()to the in-memory store so hydration preserves event ids. 4 adapter tests (write-through, observable failure, startup hydration, full sync surface) + the in-memory store's 6 still green. This is the drop-inoptions.auditEventsStorereplacement; the only remaining #11 step for the audit log is the app entry instantiating aPrismaClient(DB infra) and injecting it — and the analogous rewire for the other in-memory admin stores. -
Audit-durability wiring chain completed in-repo. Two pieces finished the cache→durable chain:
DurableAdminAuditEventsStore.insert(event)persists a pre-formed event verbatim (id +occurredAtpreserved — the write-through cache mints the id synchronously, so cache + durable row must share it;recordmints a new id and is for first-party appends), andcreateDurableAuditSink(store)adapts the durable store to the BFF'sDurableAuditSinkport (record→insert,recentForHydration→listAcrossOperators). 2 new unit tests (insert id-preservation, sink routing);@oshun/persistenceunit suite 53 green. The full chain — durable store ← sink adapter ← write-through adapter ← BFFoptions.auditEventsStore— is now in-repo + verified end to end; the sole remaining runtime step is the app entry constructing the store over a realPrismaClient(DB infrastructure + deploy/env config). -
Veritas contradiction loop — execution (the emitter half). The
contradiction/module shipped the pieces (runContradictionProbe→ triage,routeContradictions,buildMonitoringEntry/MonitoringQueue) but nothing composed them at runtime — the loop never ran, the queue was in-memory only, and no event fired when a contradiction was detected (the same "logic exists, nothing consumes it" shape as the retraction cascade). AddedexecuteContradictionLoop(contradiction/execution.ts): probe → route → build entry → enqueue (durably, via the injected queue) → publishveritas.contradiction.routings.dispatched. Enqueue precedes publish (fail-closed); a no-contradiction sweep is still recorded for audit but publishes nothing; reader surfaces are never mutated (routings go to a reviewer). Infra-free via injected ports (SophiaProbeClient,MonitoringQueue, event port), mirroring the retraction-cascade emitter; the app boundary wires a durable queue +IEventBus. 3 tests (publish-on-found, record-but-no-publish-when-clean, enqueue-before-publish ordering). Full@oshun/domain-veritassuite 309 green; typecheck clean. (The downstream reviewer-action + Sophia re-grounding consumers remain out-of-repo.) -
Yemaya server-side PNG codec (bitmap-decode engine). Image-layer content had no decoder (skipped). Added
png-codec.ts:decodePngparses the chunk stream, verifies each chunk CRC-32, inflates IDAT, and reverses all five scanline filters (None/Sub/Up/Average/Paeth) into aRasterImage(8-bit RGB + RGBA, non-interlaced; other variants throw rather than mis-decode);encodePngwrites a valid RGBA PNG. DEFLATE uses Node'szlibvia a dynamic import, so a browser bundle is unaffected (the import only runs when the codec is called, server-side). 6 tests: losslessencode→decoderound-trip (exact bytes), RGB→alpha-255 decode, Sub + Up filter reversal, malformed / unsupported-colour-type rejection, and CRC-corruption detection. Full@yemaya/rendering-pipelinessuite 1560 green; typecheck clean. -
Yemaya textured image layers (the codec, consumed). Wired the PNG codec into the composition:
rasterizeCompositionnow acceptsoptions.textures(layer-id → decodedRasterImage), and a newrasterizeTexturedLayersamples the texture through the full layer transform — super-sampled, premultiplied accumulation gives edge AA + a box-filter on minification; partial-coverage edges get fractional alpha; an image layer with no texture is still skipped (no fabrication). 3 tests, including an end-to-end decode-PNG → texture → composite (each quadrant of a 2×2 texture lands in the correct canvas region). Full@yemaya/rendering-pipelinessuite 1563 green; typecheck clean. -
Yemaya bitmap-font text renderer. Text-layer content had no renderer (skipped). Added
text-render.ts:renderText(text, atlas, color)lays a string out left-to-right with newline handling and blits each glyph's lit pixels into aRasterImage(+measureText). The glyph atlas is injected (a TTF rasteriser or shipped bitmap font is the app's asset, the same split as image textures); rendered text composes via the existing texture path. 6 tests against a hand-authored 3×5 font with exact pixel + layout assertions (glyph blit, inter-glyph advance,\nwrap, missing-glyph skip, fallback glyph). Full@yemaya/rendering-pipelinessuite 1569 green; typecheck clean. Out of scope (HarfBuzz-class libs / a font asset): complex shaping (ligatures, kerning pairs, bidi, complex scripts) and the production font atlas. The Yemaya CPU render pipeline is now feature-complete (compositing, blend modes, AA, 12 effects, masks, image textures, text); GPU/wgpu acceleration is the only remaining item, and this CPU path is its reference. -
BFF server-side idempotency middleware (P1 #3 — the spec-mandated "first step of every write"). ARCH §5 + the request-lifecycle diagram make idempotency the first thing a keyed write hits, yet the BFF had zero server-side idempotency (the only
idempotency.tsin-repo was the clientIdempotencyMiddleware, which dedupes one caller's in-process retries and cannot make a write replay-safe across the network). Addedapps/oshun/bff/src/middleware/idempotency.ts: a FastifypreHandler/onSendpair over an injectableBffIdempotencyStoreport (defaultInMemoryBffIdempotencyStore— atomic reserve, TTL'd replay records, expiring pending locks, bounded LRU eviction). Opt-in perIdempotency-Keyheader so existing keyless writes are unchanged; on a keyed unsafe method (POST/PUT/ PATCH/DELETE) it reserves the key (tenant-scoped, so one tenant's key can never collide with another's), and on a same-key retry replays the stored status + body + replay-safe headers withIdempotent-Replayed: truewithout re-running the handler (mutation happens exactly once). A concurrent in-flight duplicate gets409 idempotency_in_progress; key reuse with a different request fingerprint gets422 idempotency_key_reuse(fingerprint computed with the samecreateIdempotencyFingerprintthe client uses, so reuse detection is identical on both sides). Status policy: 2xx and deterministic 4xx are cached; 5xx / 408 / 409 / 425 / 429 are released so a retry re-runs (a transient verdict is never pinned to the key); streams/Buffers are never cached. Wired intocreateAppafter tenant/residency resolve, with anidempotencyStoreoption onOshunBffAppOptionsso a Redis/Postgres-backed store drops in for cross-instance replay safety (the same in-memory-default + injectable-durable-port pattern the admin audit-events store uses; the durable backing is the deploy-infra step). 14 known-answer tests (exactly-once replay, distinct-key re-run, keyless/safe-method pass-through, 422 reuse, concurrent 409 then 200, 400 invalid key, cached 404, 201+Location replay, uncached 429/5xx, tenant-scoped isolation, expiring pending lock) + an end-to-end wiring test through the realcreateApp. Full BFF suite 1611 passed / 22 skipped (the always-on hooks disturb no existing route; OpenAPI runtime-drift test still green); lint + typecheck clean. With this, ARCH §5's idempotency requirement is met in-repo — only distributed rate-limiting remains from the §4 #3 line. -
Studio findings→publish-gate loop closed (P1 #7).
evaluateAuthoringWithPolicyemitsblock-severity findings (e.g. a tone-policy banned phrase), but nothing consumed them at the gate —EditorialGate.satisfiedandevaluatePublishReadinesswere binding-only and caller-supplied, so a blocking finding only surfaced in review and did not block publish. Closed the loop in three places, all backward compatible: (1)editorialGateFromAuthoringFindings(findings)(editorial-lifecycle/lifecycle.ts) folds the findings into a requiredEditorialGatethat is unsatisfied iff any finding isblock-severity, sotryEditorialAdvance(approved→published)is refused while a blocking finding stands (warn/infonever gate); (2)evaluatePublishReadinessnow takes optionalevaluationFindingsand reportsmissing: ['blocking-findings'](with the offending findings attached) when any block finding exists, even if every binding is satisfied; (3)evaluateHotfixrefuses withblocking-findings-presentwhen a block finding exists — tone-policy is non-negotiable per the pipeline contract, so a banned phrase cannot be hotfixed around. 8 known-answer e2e tests (findings-publish-gate.test.ts) drive a real banned-phrase document through evaluate → gate-refused → readiness-not-ready → hotfix-refused → pipelinemode: blocked, plus the warn-only control that stays publishable. Existing signatures unchanged (the optional fields and the newblocking-findingsunion member don't disturb the prior callers/tests); full@oshun/studio-authoringsuite 114 passed; lib + spec typecheck + lint clean. Closes the §9 exit-criterion gap "Studio authoring/.../release-gate enforcement" for the authoring-findings half (Sophia/Isis/rights bindings were already enforced; what was missing was the findings→gate binding). -
Agentic-Studio governance executor — decisions now act (P1 #6). The budget / kill-switch / throttle modules each produced a verdict (
checkBudget,decideExecution,acquireToken) but nothing consumed them at runtime: there was no orchestrator that terminated a run, and the run state machine had nokilledstatus — so "budgets honored, kill switches enforced" could not hold end to end. Closed it: (1) added the terminalkilledRunStatus(distinct from operatorcancelledand errorfailed)- a
kill()run-control (mirrorscancel, audit kindkill), and foldedkilledintoTERMINAL_STATUSES, the dashboard's recently-completed bucket, and theAdminAgenticRunStatuscontract DTO + its bucket switch so the operator surface can represent an enforced kill; (2) builtruns/executor.tsadmitToolCall— the tool-call admission seam the dispatcher calls before every tool call: it runs the governance checks in safety→cost→rate order and a kill switch (decideExecutionblocked) or an exhausted budget (checkBudget→exceeded) terminates the run (killed, terminal) with an audit event + the operator's user-visible status copy;warn/gracebudgets admit-with-warning; an empty throttle bucket yields back-pressure (throttled+retryAfterSeconds, run not terminated); kill switch takes precedence over budget over throttle. Pure (returns next state; caller persists +consumeBudget). 10 known-answer tests (admit, kill-switch→killed with audit, budget-exceeded→killed, warn→admit-with-warning, throttle back-pressure, kill-switch-over-budget precedence, already-terminal refusal, no-throttle admit,killcontrol transition + terminal-refusal). Full@oshun/agentic-studiosuite 234 passed (no existing test broke on the new status);@oshun/contractslib typecheck + 30 agentic-contract tests green; lib + spec typecheck + lint clean. Moves §9's "Agentic Studio … budgets honored, kill switches enforced" from ❌ to 🟡 — the enforcement path exists and is tested; wiring the seam into the out-of-repo generation runtime is the remaining step.
- a
See the commit(s) accompanying this report for diffs and the verification (typecheck/test) output.
9. V1 Exit-Criteria Checklist#
Exit criterion (from V1/features.md §"V1 Exit Criteria") |
Status |
|---|---|
| Customer web & mobile feel like one coherent product across all 6 domains | ❌ — hub pages are fixtures; not BFF-backed |
| Tara is visibly the product center | ✅ — shell ordering is Tara-primary (real) |
| Nisaba & Metis fully integrated (not just routed) | ❌ — Nisaba logic is integrated; Metis runtime is disconnected |
| Sophia grounding visible wherever evidence matters | 🟡 — Sophia layer real; surfaces show canned grounding |
| Cross-domain continuity useful, credible, tested | 🟡 — shell continuation logic real & tested; data is fixtures |
| Admin can operate ALL listed governance workflows | ❌ — T&S/Support/Metis-governance missing; admin BFF non-durable |
| Studio authoring/calendar/asset/.../release-gate enforcement | 🟡 — logic real; findings→gate not bound; no persistence |
| Agentic Studio operational w/ governance gates enforced & budgets honored | 🟡 — executor now enforces kill-switch/budget → run termination (§8); orchestrator-to-runtime wiring pending |
| Tenant Console (SSO/SCIM/OneRoster…) isolated from operator admin | 🟡 — logic real; forgeable session; LTI/SCORM missing |
| Iris/Psyche/Lilith/Sophia/Isis/Metis ownership true in product | 🟡 — true in libs; not wired to runtime for Iris/Isis/Metis |
| External model sources cannot bypass review/rights/safety/provenance/Isis gates | 🟡 — Isis gates enforce & block, but Isis is unwired to any surface |
| Metis high-stakes outputs emit claim-level evidence & pass 7 gates | ❌ — 7-gate pipeline doesn't exist; worker data fabricated |
| Public website, store listings, deep links, status page launch-ready | 🟡 — deep-link/nav real; landing is fixture/CMS-later |
| Recommendation candidate gen, signal ingestion, offline eval, observability operational | 🟡 — candidate/signal/ranking real; eval/observability are manifests only |
| Aja embodied-instruction ready or explicitly deferred w/ scope | 🟡 — bounded adapter exists; add explicit deferral note |
| All critical workflows have risk-tiered automated verification | 🟡 — strong unit/contract tests; integration/enforcement tests absent |
| Accessibility/perf/security/resilience/observability/runbooks satisfy launch gates | ❌ — no real persistence/observability runtime; render substrate simulated |
Net: 0 of the headline exit criteria are fully met; most are "logic-ready, integration-pending."
_This report is generated from direct source reads with file:line evidence.
Where an audit could not reach a backend (e.g. out-of-repo Nyx ephemeris
service, Metis Python backend, services/psyche/_), that is stated explicitly
rather than assumed working.*
10. Executable Remediation Tickets#
The remaining gaps are integration/infra/decision work — but they are far more tractable than "build from scratch," because the hard pieces already exist in-repo. Confirmed scaffolding the tickets below build on:
libs/oshun/persistence— a real Prisma schema (prisma/schema.prisma, 85 models) already models every V1 domain, includingVeritasRetractionCascade,CrossCuttingConsentRecord,CrossCuttingMemoryScope,CrossCuttingIncident,CrossCuttingSupportCase,CrossCuttingAgentRun,CrossCuttingTenant, plus all Tara/Arete/Nyx/Nisaba/ Metis tables. Generated client undersrc/generated/client.libs/shared/event-bus— real outbound delivery + topic-registry + HMAC signing (event-bus.ts,outbound-delivery.ts,topic-registry.ts).libs/shared/queue,libs/shared/data-residency, **libs/oshun/auth- BFF
authz** — real, tested substrates to depend on.
- BFF
- The domain logic (recall scoring, cascade planner, gate enforcement, entitlement math, crisis classifier) is real and unit-tested — these tickets wire it, they don't re-implement it.
Each ticket lists the in-repo pieces to leverage, the concrete steps, and the external input a human/team must supply (the reason it can't be finished autonomously).
T1 — Build the runtime persistence layer, then back substrate adapters#
Investigated finding (decision point): persistence is build-time only.
contract-persistence-registry.tsis a spec (V1_OBJECT_PERSISTENCE_CONTRACTS) that drivesprisma-rendererto generate the 85-model schema; the models are a generic contract-envelope store (each row = typed-JSON contract columns +tenantId/contractSchema/sourceRecordId/payloadHash+ tombstone fields). What does not exist is any Prisma-client-backed runtime repository (no upsert/fetch/tombstone against a live client). So T1 is a build, not a wire.
- Step 1 (foundational) — ✅ DONE this pass. Built
libs/oshun/persistence/src/contract-record-repository.ts: a genericContractRecordRepositorywithput/get/tombstone, driven by the samegetObjectFieldProjectionsthe schema renderer uses (so columns cannot drift), serializing each contract field to its column (DateTime string→Date, arrays/objects→Json) + the control envelope (tenantId/contractSchema/contractVersion/sourceRecordId/payloadHash+ tombstone), keyed on the[tenantId, contractSchema, sourceRecordId]identity. Includes a stable order-independentcomputeContractPayloadHashand aprismaDelegateResolverto bind a realPrismaClient. Type-clean under the lib's real typecheck; 10 unit tests (serialize/control-envelope/hash/ round-trip/tombstone-exclusion) + full persistence suite green. One generic repository serves all 85 models. Also added the ergonomic facadeContractPersistenceService(contract-persistence-service.ts) + factorycreateContractPersistenceService(prismaClient): callers persist by(domain, contractName)— e.g.service.put('veritas', 'Story', record, ctx)— with registry resolution + fail-fast on unknown contracts (5 tests). So the foundation is now consumable by name, not just present. Real-DB round-trip verified:contract-record-repository.integration.test.tsruns the full put→get→list→idempotent-reput→tombstone cycle for a realtara:DurationBucketcontract against a migrated dev Postgres (via the generated client + aPrismaPgdriver adapter), and passes — proving the serialization, control envelope, and identity keying match the generated client/schema end-to-end. The test is gated behindOSHUN_V1_DATABASE_URLso it skips cleanly in DB-less CI. T1 Step 1 is complete and end-to-end verified. - Step 2: implement concrete substrate adapters on top of it — e.g.
PrismaIrisMemoryApiAdapter(Iris contracts →CrossCuttingMemoryScope/CrossCuttingConsentRecord); replace the admin BFF in-memoryMapstore; inject via the existingcreateCanonical*Adapteroptions. - External input / decision: Postgres is available for dev
(
docker compose -f docker/docker-compose.dev.yml up -d, migrations applied), so this is autonomously buildable — but the repository design (serialization, connection/pooling, transaction boundaries) and per-substrate contract→model fit are architecture decisions warranting owner review. Foundational, reviewed build — T2/T4 and the admin/Iris durability gaps all layer on top.
T2 — Veritas retraction cascade execution#
- Leverage:
planVeritasSourceRetractionCascade()(pure planner, done);VeritasRetractionCascadePrisma model;libs/shared/event-bus. - Steps: add BFF
POST /api/oshun/domains/veritas/claims/:id/retract→ persist tombstone (Prisma) → run planner → publishveritas.claim.retractedvia event-bus → Sophia subscriber invalidates evidence packs + emitssophia.evidence.invalidated. - External input: the Sophia service's invalidation endpoint/consumer
(out-of-repo
libs/sophia/*client wiring) + event-bus broker config.
T3 — Isis dispatch surface wiring#
- Leverage:
@oshun/generation-control-isis(gate enforcement done + tested, zero importers today);IsisGenerationControlApiAdapterinterface. - Steps: add a BFF/admin route that routes generation through
dispatchGeneration/routeApprovedOshunMediaGenerationRequest; implement the concreteIsisGenerationControlApiAdapteragainst the real Isis runtime; add the tsconfig path alias; build the deterministic tier resolver + deny-by- default surface guard for the 4 audience tiers. - External input: the Isis execution runtime (
apps/isis/libs/isisprovider clients) endpoint contract.
T4 — Privacy DSAR true deletion + cross-domain tombstone cascade#
- Leverage: the privacy state machines (done); per-domain Prisma tables;
tombstone-semanticsin@oshun/persistence; event-bus. - Steps: make
advanceToHardDeleteactually delete rows + write tombstones via Prisma; implement Iris scope enumeration → fan tombstone writes to every domain table with per-tombstone audit attestation; real cryptographic shred. - External input: DB + the audit-platform sink; legal/retention policy confirmation for shred semantics.
T5 — Metis 7-gate release pipeline + runtime#
- Leverage: the 4 enforcing gates that exist (safety, rights, academic-
integrity, standards) + the scattered grounding/pedagogy/drift helpers;
libs/metis/*algorithms (IRT, mastery, knowledge-graph — all real). - Steps: build a single
MetisReleaseGatePipelineobject that runs grounding→pedagogy→safety→rights→academic-integrity→standards→drift and emits a release verdict; wirelibs/metis/*into an in-repo runtime path (or import the Python backend into scope). - External input: decision on TS-runtime vs. the out-of-repo Python backend; grounding/pedagogy/drift gate thresholds.
T6 — Real on-chain address derivation (Aje: Tron/TON/Ergo/Cardano)#
- Leverage: the correct EVM derivation already in-repo
(
xpub-watcher.ts: secp256k1 → keccak256 → 20-byte address);@noble/*. - Steps: Tron = EVM-20-byte →
0x41prefix → base58check; TON = v4r2 StateInit cell-hash; Cardano = CIP-1852 → bech32addr1; Ergo = P2PK. - External input (hard requirement): authoritative known-answer test vectors (privkey/xpub → canonical address from tronweb / ton-core / cardano- serialization-lib). Financial code must be verified against these, never shipped from memory.
T7 — Yemaya render kernel + Living Scenes pixel pipeline#
- Leverage: the real Conductor/scheduling, scene-score schema, provenance/ takedown/shareability decision logic (all done); the contracts.
- Steps: implement the actual render/blend kernel (Rust/wgpu per CLAUDE.md → WASM bridge), real C2PA Ed25519/X.509 signing + watermark embedding + container muxing, re-render-from-score, PSE/strobe live-frame detector, durable artifact persistence.
- External input: the largest item — a graphics/media engineering effort + signing-key infrastructure. Genuinely multi-week, specialist.
T8 — Nyx ephemeris + power-user surfaces; web consumer-hub BFF wiring#
- Leverage: the real Nyx contracts/adapter/notification-timing (done); the Skyfield-class ephemeris adapter seam.
- Steps: stand up the Nyx ephemeris service behind
OSHUN_NYX_API_BASE_URL; build the 19/domains/nyx/*power-user pages; wire the 6 consumer-hub pages offlilith-data/*fixtures onto the BFF (and decide fail-closed vs. fixture for prod, per §3). - External input: the ephemeris service deploy + product decision on the fixture-backed hub stopgap.
Sequencing: T1 unblocks the most (most "no DB" gaps); then T2/T3/T4 (wiring on top of T1's persistence); T5 in parallel (Metis-team); T6 once vectors are supplied; T7 is the long pole (media engineering); T8 alongside.