Disciplines · Audits

Monorepo Architecture & Organization Audit — 2026-07-16

The monorepo is polyglot (TypeScript, Rust, Python, C++/UE, Swift, Solidity) and poly-product.

8sections74 minread

On this page

Deep audit of the Oshun monorepo covering technical debt, architecture, DRY, repo organization, folder structure, conventions, build system, dependencies, CI/CD, testing, and documentation. Every finding below is backed by a measured count or a concrete file path collected on 2026-07-16 from branch oshun-v1-nisaba.

Meta-note: this report was written at the repo root (the convention at the time — 71 sibling reports). The R-3 migration moved it, together with 53 sibling reports, to docs/audits/ on 2026-07-16. Tooling-parsed reports (V_SERIES.md, the V1_V9_* 2026-07-15 set, DEPENDENCIES.md, TODOS.md, ISIS_TODOS*.md, ARCHITECTURE.md, RESPONSIBILITY_SPLIT_RECOMMENDATION.md, CONTENT_GENERATION_CAPABILITY_MATRIX.md) and active planning docs (V_SERIES_AMBIENT_RAIL*.md) stay at root until their tooling is repointed.


0. Scale of the subject#

Metric Value
Tracked files 135,430
Git pack size 1.19 GiB
Nx projects (project.json) 3,421 (3,007 under libs/)
Workspace package.json files 3,264
Rust crates (Cargo.toml) 1,437 — 505 of them independent [workspace] roots
Python projects (pyproject.toml) 83
tsconfig files 7,044
vitest configs 2,654
tsconfig.base.json 172 KB, 2,164 path aliases
Root package.json scripts 549
GitHub workflows 148 (27,736 LOC of YAML)
libs/ domains 57 (largest: neith 597 projects, kalika 192, aphrodite 184, maya 151, psyche 134)
apps/ entries 34
Products V1–V10 (ten distinct products on a shared platform) + ~50 domain libraries

V10 addendum (same day as this audit): V10 "The Rail" (ambient companion layer over V1–V9) was seeded on 2026-07-16, concurrent with data collection. It so far consists of V10/V_SERIES_AMBIENT_RAIL.md + V10/V_SERIES_AMBIENT_RAIL_TODOS_2026-07-16.md (moved into the V10/ product tree later on 2026-07-16, resolving their finding A-5 entries) and libs/contracts/src/v10/ (channel contract + spec — correctly placed per the contracts convention). The V10/ product tree now also carries V10_features.md/V10_ARCHITECTURE.md, so V10 does not otherwise affect the measurements below; it is, however, the natural first adopter of the single-placement convention recommended in R-8 before it grows three roots like its siblings.

The monorepo is polyglot (TypeScript, Rust, Python, C++/UE, Swift, Solidity) and poly-product. Much of what follows is the natural sediment of very fast phase-driven growth; the good news is that most of the top-payoff fixes are mechanical.


1. Executive summary — top findings by severity#

# Severity Finding Section
1 Critical ~850 MB of the 1.19 GiB git pack is committed artifacts: 577 MB Swift .build/ outputs (6,140 files), 131 MB generated HTML (3,815 files), 119 MB git-bundle backups, 24 MB Hardhat artifacts/ A-1..A-4
2 Critical DRY collapse at the utility layer: 2,844 files define their own clamp, 86 exported generateId implementations, 14 domain-local CircuitBreaker classes, 5 competing sleep implementations inside libs/shared itself E
3 High 505 independent Cargo workspaces (no shared dependency catalog, Cargo.lock globally gitignored yet 64 committed) D-5
4 High Deployment/IaC config split across 4 top-level dirs with three terraform roots (deploy/terraform, infra/terraform, infrastructure/terraform) B-2
5 High Documentation exists in at least 8 root-level surfaces (docs/, docs-center/, DOMAINS/, systems/, platform/, 5 × *_WALKTHROUGH/, TODOS/, 71 root reports) with md→html twins committed for ~2,768 files B-4, A-3
6 High CI: 148 workflows, 56 of them near-identical v4-* clones (53-line skeleton differing only in path filters); only 1 reusable (workflow_call) workflow G
7 High Root package.json carries 441 verify:phase-N scripts + 26 scripts/verify-phase-*.mjs — process artifacts fossilized in the build interface A-5, D-4
8 Medium Build-target definitions are hand-rolled per project: 6,447 nx:run-commands expressing the same tsc/vitest/eslint intent ~10 different ways C-1
9 Medium Python toolchain drift: nx.json references {workspaceRoot}/ruff.toml and root pyproject.toml that do not exist; 0 lockfiles for 83 Python projects C-3, D-6
10 Medium Four HTTP server frameworks in production use (fastify 114, hono 67, express 19, NestJS 16 packages) D-3
11 Medium Test conventions split four ways (9,834 .spec.ts vs 5,286 .test.ts colocated, plus __tests__/ and tests/) F-1
12 Medium Domain-boundary governance is real but leaky: 44 depConstraints, growing allow-list, 451 untagged projects, apps/oshun/web opted out entirely, isis↔yemaya bidirectional coupling H
13 Medium Four BFFs with zero shared substrate (1,987 vs 385 vs 9 vs 0 source files); @oshun/gateway is actually a Traefik CLI, not an HTTP layer H-3
14 Medium scripts/isis alone is 2,256 files (78% of scripts/), 1,088 of them near-identical generate-v2-* codegen shims; apps/urania is a fully dead app G-5, H-6
15 Low CI trigger/toolchain drift: 21 jobs pin Node 24 vs .nvmrc 22; two "nightly" workflows have no schedule: trigger G-2b

Overall dimension health (1 = severe debt, 5 = healthy):

Dimension Score One-line verdict
Git/repo hygiene 1.5/5 Artifacts and generated files dominate the pack
Folder structure 2/5 Strong domain idea, drowned in top-level sediment
Build system (Nx) 3/5 Affected/caching/tags exist; target definitions chaotic
Dependency mgmt 3.5/5 Catalog + isolated linker are genuinely good; overlap debt remains
DRY 1.5/5 Canonical shared libs exist but migration never finished
Conventions 2.5/5 Strict TS base + commitlint exist; naming/test/docs conventions splintered
CI/CD 2.5/5 Real affected-based CI; workflow-count explosion
Architecture 3.5/5 Domain isolation mostly holds; god-files and framework spread
Documentation 2/5 Enormous volume, no single navigable source of truth

2. Methodology#

  • Full inventory passes over git ls-files (counts, sizes, extensions, directory distribution).
  • Config forensics: nx.json, tsconfig.base.json, eslint.config.js, pnpm-workspace.yaml, .npmrc, .gitattributes, husky hooks, commitlint.
  • Cross-domain import-edge mapping via scoped-import greps for 10 domains.
  • Two sequential read-only exploration agents (per session-limit rules): one for cross-library duplication, one for apps/scripts/CI granularity.
  • Executor/test/naming variance measured by hashing and tallying config files.

3. Findings#

A. Repo & git hygiene#

A-1. 577 MB of Swift build artifacts are committed. libs/psyche/ios-sdk/.build/ (3,838 files) and apps/bellona/remote-host/macos/.build/ (2,302 files) are tracked, including two 67 MB data.mdb index files and dozens of multi-MB .pcm module caches. These are per-machine SwiftPM outputs; they invalidate on every Xcode/Swift version change and bloat every clone forever (git history keeps them even after deletion).

A-2. 119 MB of git-bundle backups are committed. backups/ holds four .bundle files (lilith-*, yemaya-*, Jan 2026). A git repo committed inside a git repo is pure history bloat; these belong in object storage (the repo already has MinIO/S3 conventions).

A-3. 131 MB / 3,815 generated HTML files are committed. 2,768 are exact .md.html twins (docs-center readers, vdocs, V1–V9 feature docs, all five *_WALKTHROUGH/ dirs, DOMAINS/), plus vdocs-search-index.js (1.2 MB) at the root. The pre-commit hook (.husky/pre-commit) regenerates and re-stages them on every docs commit, so every documentation change commits twice its size in artifacts. Rendered HTML is a build output; CI already has vdocs-html-fresh.yml proving it can be built on demand.

A-4. 24 MB of Hardhat compilation artifacts are committed. apps/lilith/contracts/artifacts/ (172 files, incl. two ~12 MB build-info/*.json). Correction during R-1 execution: the contract ABI JSONs (1.4 MB, under artifacts/contracts + artifacts/@openzeppelin) are read at runtime by four apps/lilith/svc-blockchain clients, so they are load-bearing data and stay tracked; only build-info/ (22.7 MB of compiler debug metadata, referenced by nothing) is a pure artifact and was untracked.

A-5. The repo root is a landfill. 113 tracked root-level files, of which 71 are .md audit/plan/analysis reports (SCREAMINGSNAKE, dated), plus an 8 MB TODOS.md _and a TODOS/ directory with 247 phase files, plus dead one-off scripts untouched since 2026-02-21 (check-indexes.ts, check-schema.ts, check-services.js, test-tara-*.ts, test-veritas-api.ts, update-exports.js, .audit-rewrite.mjs, insights-report.md). Domain- specific configs also sit at root (typedoc.kalika.json, lighthouse.config.js). docs/audits/ already exists and is the right home for the reports.

A-6. LFS is configured but unused. .gitattributes declares 93 LFS patterns, yet only 20 files are actually in LFS. The 67 MB .mdb files, the V5 12 MB animation_catalog.json, and 11.5 MB content-coverage/seed-registry.v1.json all live as plain git objects.

A-7. Cargo.lock policy is self-contradictory. .gitignore:288 ignores Cargo.lock globally, yet 64 lockfiles are force-added. Rust guidance is: commit lockfiles for binaries/applications, optional for libraries — the current state is neither, so builds of the other ~440 workspaces are not reproducible.

A-8. Stale top-level architecture docs. ARCHITECTURE.md last touched 2026-04-23 — before most of the current 57 domains existed. DEPENDENCIES.md (128 KB) and RESPONSIBILITY_SPLIT_RECOMMENDATION.md (65 KB) similarly frozen.

B. Folder structure & top-level taxonomy#

B-1. The top level mixes ~25 different concepts. Products (V1–V9), platform code (apps/, libs/, services/), infra (infra/, infrastructure/, deploy/, docker/), docs (8+ surfaces), tooling (tools/, scripts/, testing/, tests/), stray singletons (clients/ with one entry, integrations/ with one entry, sdks/ with three, tara/ assets, platform/ and systems/ which are actually documentation), and working dirs (tmp/, dist/, models/, test-results/ — untracked but permanently present). A newcomer cannot tell code from docs from generated output at the root.

B-2. Four overlapping infrastructure dirs, three terraform roots. deploy/terraform (has its own DEPRECATED.md but still ships main.tf + deploy.sh), infra/terraform (ECS/ALB/OIDC modules — the post-Fargate- migration active one), infrastructure/terraform (bootstrap/modules/env layout, plus infrastructure/helm which contains a DEPRECATED.md). Kubernetes manifests live in infra/k8s, deploy/kubernetes, and infrastructure/helm. A vendored Pulumi module hides inside infra/terraform/iris/modules/pulumi (mixing IaC toolchains; .nxignore has to special-case it). There is no README at any of the four roots declaring which is live.

B-3. V-series products are fragmented across three roots each. V3 = V3/ (docs+UE+ops) + apps/v3/ (Rust services + web) + libs/v3/ (TS libs); same pattern for v6/v7/v8/v9 (and V2/V4/V5 keep services/, web/, scripts/ inside their root dirs instead). Two placement conventions exist simultaneously, and product code is never adjacent to its docs. Path-filtered CI (56 v4-* workflows) is a direct symptom of this scatter.

B-4. Documentation has ≥8 competing surfaces. docs/ (6,241 files, 26 topic subdirs incl. its own domains/), docs-center/ (rendered doc portal, 305 committed HTML), DOMAINS/ (326 files: per-domain architecture/features/ specifications md+html), systems/ (93 per-project one-pagers), platform/ (14 md+html), five *_WALKTHROUGH/ dirs (1,868 md+html twins, 39 MB), root reports (71), TODOS.md + TODOS/, plus vdocs-* index files at root. Domain documentation alone exists in three places (DOMAINS/aphrodite/*, docs/domains/*, systems/lib-aphrodite.md). There is no index that says which surface is canonical.

B-5. services/ vs apps/ split is arbitrary. services/ holds three deployables (concordia, metis, psyche) while ~30 other deployables live under apps/*; meanwhile apps/infra is not an app at all. nx.json even declares a custom servicesDir in workspaceLayout. One convention should win.

B-6. Naming style varies at every level. Nested product apps (apps/oshun/web) vs flat hyphenated (apps/euterpe-studio-web, apps/neith-vault); SCREAMING_CASE doc dirs (DOMAINS/, WALKTHROUGH/) vs lowercase (docs/, docs-center/); an orphan libs/tsconfig.test.json file sitting between domain directories; apps/urania exists with no matching libs/urania or docs entry.

C. Build system & Nx#

C-1. Target definitions are hand-rolled 3,400 times. Executor census: 6,447 nx:run-commands, 1,646 @nx/eslint:lint, 1,512 @nx/vite:test, 1,170 @nx/js:tsc, 148 esbuild, plus stragglers (2 × jest, 2 × @storybook/angular:* — Angular is not in the stack). The same intent is spelled at least ten ways (tsc --noEmit / npx tsc --noEmit / pnpm exec tsc -p tsconfig.lib.json / tsc -p tsconfig.build.json / …). This defeats targetDefaults, makes cache inputs inconsistent, and means every convention change is a 3,000-file migration. Nx plugin inference (or a single generator

  • codemod) exists precisely to avoid this.

C-2. parallel: 3 in nx.json throttles every run-many/affected on a box that can afford more; CI and the 8-vCPU dev box both inherit it.

C-3. Named-input drift. pythonLint references {workspaceRoot}/ruff.toml and {workspaceRoot}/pyproject.toml; neither file exists (ruff invocations live per-project as python3 -m ruff check .). python input references poetry.lock; zero are tracked. Result: Python lint/test caching keys are built from phantom files, and per-domain named-input blocks (irisShared, v3Production, v6Production, v7Production…) accrete in nx.json instead of a uniform convention.

C-4. Boundary tags don't cover the graph. 2,550 of 3,421 projects carry tags; 451 have none (446 in libs/neith). The eslint depConstraints (44 sourceTag rules) therefore can't constrain them, and there is no wildcard catch-all rule, so an untagged project can depend on anything. The rule is also disabled wholesale for apps/oshun/web (eslint.config.js:985), and the allow list of cross-domain exception packages keeps growing (15 entries with phase-numbered comments).

C-5. Two tsconfig-preset systems coexist. configs/tsconfig/{base,library, node,react,service}.json is a clean preset layer — used by only 83 files, while ~3,300 tsconfigs extend root tsconfig.base.json directly (592/600 sampled). The base is genuinely strict (strict, verbatimModuleSyntax, noUnused*) — good — but 324/600 sampled libs re-declare "strict": true redundantly, and emitDecoratorMetadata/experimentalDecorators are ON globally for the benefit of 16 NestJS packages. noUncheckedIndexedAccess and exactOptionalPropertyTypes are absent at base (already proven viable in the mobile app).

C-6. tsconfig.base.json is a global contention point. 172 KB / 2,164 aliases, listed in sharedGlobals, so every new library invalidates the whole Nx graph (the pre-commit hook comment documents the 2,449-project typecheck stampede this caused). Two aliases are dead (@oshun/logger, @oshun/logger/*libs/shared/logger does not exist; 0 importers).

**C-7. Nx lint plugin excludes lilith/**, yemaya/**, apps/**** — those projects need hand-declared lint targets or silently go unlinted; combined with C-1 heterogeneity it is impossible to say from config alone what is actually linted.

C-8. nx release config scope is near-empty (verified 2026-07-16). release.projects: ["libs/*", "apps/*"] — slash-containing patterns match project roots, and almost all projects are nested two levels deep (libs/<domain>/<lib>), so the globs reach only the handful of single-level roots (libs/contracts, libs/proto, libs/openapi, apps/euterpe-studio-web…). release.yml invokes pnpm nx release version/publish on dispatch, and a second release mechanism (changesets: version-packages/release scripts) coexists in package.json. Widening the globs would change publish scope for ~3,300 packages, so the repair needs an explicit decision on which mechanism owns releases — flagged, not auto-fixed.

D. Dependency management#

D-1. What's good: pnpm catalog with 8,803 catalog: references, isolated node-linker with curated public-hoist-patterns, save-exact, renovate config, a single React/Next/Expo version line (no React 18/19 split), no moment/dayjs. This layer is healthier than most monorepos.

D-2. Overlapping/legacy packages persist. Both bcrypt and bcryptjs (6 users); crypto-js (2 users) alongside the @noble/* suite; axios (6)

  • node-fetch (3) + native fetch wrappers (78 hand-rolled — see E); uuid (69 users) + nanoid (32) + 86 hand-rolled generateIds; jest in 16 packages vs vitest in 2,100 (the 16 include legit Expo/RN presets, but also 2 @nx/jest:jest stragglers); 103 jest-scoped imports inside libs/lilith alone.

D-3. Four HTTP server frameworks. fastify (114 packages), hono (67), express (19), NestJS (16). Each brings its own middleware/plugin ecosystem, auth glue, and error semantics; libs/shared/gateway cannot cover four stacks. No documented decision says which is default for new services.

D-4. 549 root scripts, 441 of them verify:phase-N. Plus 10 test:*, 10 openapi:*, etc. The phase-verify family (backed by 26 scripts/verify-phase-*.mjs) is process history, not build interface — it belongs in one parameterized runner (node scripts/verify-phase.mjs 42) or in the TODOS tooling, not as 441 npm scripts loaded into every pnpm run completion.

D-5. Rust: 505 independent workspaces. No root workspace, no shared [workspace.dependencies] catalog across families; version specs drift (wgpu 29.0.1 vs 29.0.4; tokio 1.35/1.36/1.44/1.48/1.49; serde spelled 6 ways). Each workspace resolves and builds its own dependency universe — massive redundant compile time and disk (target/ per workspace). At minimum, domain-level umbrella workspaces (neith, maya, kalika, uzume, v3/v6/v7) with workspace.dependencies would collapse most of this; the existing 119 workspace = true serde entries show the pattern is already understood.

D-6. Python: 83 pyproject.toml, zero lockfiles, no root config. Ruff is invoked per-project but configured nowhere at root (see C-3). No uv.lock/poetry.lock tracked → non-reproducible environments; the on-box venv + PHOEBE_SIM_PYTHON gate pattern papers over this per session.

D-7. .env.example is a 44 KB / 388-variable monolith shared by all products. Per-app example env files (some apps have them) with a generated root aggregate would keep ownership clear and diffs reviewable.

E. DRY — duplication census (evidence-sampled across libs/)#

The platform-primitive layer (libs/shared, 52 @oshun/* libs) is real and imported by 2,750 files (top importers: @oshun/logging 423, @oshun/crypto 146, @oshun/database 145, @oshun/event-bus 113). The debt is that the migration to it was never finished, and the lowest-level utilities never got a home at all:

Pattern Independent implementations Canonical exists? Evidence sample
clamp 2,844 files (1,234 byte-identical signature) No shared math lib at all libs/kuanyin/performer-protection/src/boundary-enforcement.ts:21 and 3 identical siblings
lerp 332 files No concentrated in nous 464, aphrodite 394, isis 257, hathor 248, calliope 238 (clamp+lerp combined)
generateId/createId 86 exported defs, 548 refs No general-purpose one libs/sophia/schemas/src/ids.ts, euterpe/virtuoso, kuanyin
Retry/backoff ~34 defs, 256 referencing files Fragmented: 4 copies inside shared (http-client/src/retry.ts, gpu-dispatcher/src/retry.ts, runpod-client/src/polling.ts, types/src/legacy.ts) libs/aje/rpc/src/retry.ts, libs/yemaya/orchestration/src/execution/retry-manager.ts
sleep/delay 13 local + 5 competing copies inside libs/shared No single one libs/aje/rpc/src/sleep.ts
Circuit breaker 16 classes (14 outside shared, 2 inside) Duplicated even in shared libs/lilith/service-lib/circuit-breaker.ts, libs/iris/failover/src/circuit-breaker.ts, libs/cybele/api/src/circuit-breaker.ts, …
Logger 8 factories + 22 raw-pino imports + 2 class Logger Yes@oshun/logging (423 importers) libs/yemaya/enterprise/src/utils/logger.ts, libs/iris/core/src/logging/logger.ts
HTTP client wrapper 78 local wrappers Yes@oshun/http-client (timeout+retry+CB+SSRF-guard; only 48 importers) libs/bellona/client/src/api/client.ts, libs/veritas/b2b-sdk/src/client.ts
Result<T,E> type 8 domain redefinitions Yes@oshun/types libs/oya/common/src/result.ts, libs/seshat/common/src/types.ts
Env/config parsing 31 local loaders; 596 files read process.env directly Yes@oshun/config (40 importers) libs/galatea/core/src/config/runtime-config.ts; even libs/shared/storage/src/s3-client.ts reads env ad hoc
Postgres pool factories ~12 outside shared Yes@oshun/database (145 importers) libs/cybele/db/src/connection.ts, libs/lakshmi/db/src/connection.ts
Redis factories 32 raw-client files Yes@oshun/cache (56 importers); shared itself bypasses it in 6 libs libs/asase/infrastructure/src/cache.ts
deepClone/deepMerge 6 defs + scattered shared copies Partial libs/hathor/domain-models/src/common/utils.ts
chunk/batch ~17 defs No libs/aje/core/src/blocks/utils.ts

Config duplication mirrors code duplication: the top 8 vitest-config hashes cover ~700 identical files; 561 distinct tsconfig.json variants exist across libs where ~5 presets would do.

F. Conventions#

F-1. Test conventions split four ways. 9,834 colocated *.spec.ts vs 5,286 colocated *.test.ts vs 1,178 files under __tests__/ vs 364 under per-lib tests/. eslint carves separate override blocks for each. Pick one (colocated .spec.ts is the plurality) and codemod.

F-2. Commit-scope vocabulary covers ~40% of reality. commitlint.config.js scope-enum lists 22 domains + generic scopes, is warning-only, and is missing 30+ active domains (neith, nous, gaia, phoebe, euterpe, galatea, themis, uzume, oya, metis, mnemosyne, seshat, shakti, calliope, kuanyin, annapurna, athena, lakshmi, aglaea, airmid, v3–v9…). Memories show scope guessing (core vs nous vs neith) is a recurring commit-time stumble.

F-3. Per-library READMEs effectively don't exist (3 of 400 sampled lib dirs). The information lives far away in systems/lib-*.md and DOMAINS/, which no editor/IDE surfaces next to the code.

F-4. Package-scope naming is split. Platform libs use @oshun/* while domains use per-domain scopes (@neith/* 539, @iris/* 258, @aphrodite/* 191…). Workable, but combined with 57 mythology names there is no way to tell a domain's purpose from its name — and no registry mapping name → purpose → owner exists in-repo (DOMAINS.md is closest but 3 weeks stale and unordered).

F-5. eslint.config.js is a 1,638-line monolith mixing global policy with dozens of app-specific carve-outs (per-service override blocks for 8 lilith services, per-app storybook paths, a 15-entry allowDefaultProject list). Project-level eslint.config.js files inheriting a root preset would localize churn; today every exception edits the root file (60 KB re-parsed by every lint of 1,646 lint targets).

F-6. God files. libs/kalika/crystallography/src/diffraction/anomalous-data.ts (54,156 lines — embedded dataset as source), libs/maya/vr-studio/src/index.ts (28,261), libs/maya/standards/src/index.ts (25,021), libs/maya/renderer/src/index.ts (22,753), libs/nisaba/languages/src/classical-chinese/constants/character-database.ts (25,508), libs/yemaya/agents/src/pipelines/game-pipeline.ts (14,927). Whole libraries live in a single index.ts; datasets are inlined as source code instead of data files loaded at build time.

F-7. TODO debt is measurable but bounded: 1,432 non-test source files carry TODO/FIXME/HACK markers — notable given the zero-tolerance stub policy; most are in vendored/dataset-like code, but no burn-down list exists.

G. CI/CD & tooling#

G-1. 148 workflows / 27.7k YAML LOC, dominated by clones. 56 v4-* workflows share one 53-line skeleton (checkout → composite setup → pnpm -F @v4/scripts testpnpm -F @v4/scripts <slug>-check) differing only in path filters and slug (verified by normalized diff of v4-hall-of-fame.yml vs v4-map-lore.yml). One matrix- or generator-driven reusable workflow replaces all 56. Only 1 workflow uses workflow_call; 112 do use the shared ./.github/actions/setup composite (good foundation to build on).

G-2. Trigger drift, not broken paths, is the CI dead-weight. A glob-aware test of all 382 distinct path-filter entries found only one stale reference (v3-workspace.ymlapps/oshun/web/src/middleware.ts, which no longer exists) — path hygiene is good. But: 93 of 148 workflows serve the UE V1–V9 product lines vs 47 for the Nx apps (~63% of CI surface for the game lines); 16 workflows are workflow_dispatch-only, and only 8 have a schedule: trigger — including none for a11y-pa11y-nightly.yml and v4-nightly-feel-tests.yml, which are "nightly" in name only and never run automatically.

G-2b. Node version drift in CI. .nvmrc, engines, and the composite setup action all agree on Node 22 / pnpm 10.25.0 — but 21 workflow jobs pin node-version: 24 inline (vs 10 pinning 22), and 10 workflows bypass ./.github/actions/setup entirely with hand-rolled actions/setup-node (runpod-endpoint-*, stub-indicator-scan, tara-web-deploy, external-api-guard, api-inventory, adversarial-grep-trend, test-coherence-check). CI can pass on a Node major the repo doesn't declare.

G-3. The pre-commit hook does seven jobs (lint-staged, V2 asset-lock python, stub-scan, V5 docs validation, scoped typecheck, docs-center HTML regen + re-stage, LFS locking) — it is the de-facto CI and the reason commits are slow and sometimes surprising (HTML re-staging). Hooks should gate, not build; the HTML regen belongs exclusively to CI (its own comment admits CI is the backstop).

G-4. Main ci.yml (1,031 lines) is properly nx-affected-based for lint/ typecheck/build/test — this part is healthy — but also inlines product- specific gates (four Isis schema/taxonomy/benchmark validators) that belong in those projects' own targets so nx affected scopes them naturally.

G-5. scripts/ is 78% one domain's codegen output. Breakdown of the 2,909 tracked files: scripts/isis 2,256 (2,209 .mjs; 1,092 generate-*, of which 1,088 are generate-v2-* — one generated generator per ComfyUI/asset artifact), scripts/v3 274, scripts/lilith 140, scripts/v6 129, scripts/audit 23 (the healthy end: schema-backed, self-tested capability-truth/verification tooling), 43 loose root files. The 26 verify-phase-*-completion.mjs checkers cover non-contiguous phases (8–14, 20–26, 32–33, 39, 49, 63, 65, 82, 97, 98, 143–145, 180) — pure process residue.

G-6. Two parallel doc/codegen toolchains. Docs rendering exists twice: tools/render-docs-center.py + tools/docs_center/ (Python, canonical, hook/CI-invoked) and scripts/docs/generate-domain-docs.mjs + generate-oshun-domain-reference.mjs (Node). Code generation likewise splits across tools/codegen + tools/generators/{cybele-library,iris-library,python-service} vs the scripts/isis/generate-* fleet. No single home for either concern.

H. Architecture#

H-1. Domain isolation mostly holds. Cross-scope import sampling of 10 domains shows dominant self+shared imports (e.g. bellona: 133 self, 0 foreign; veritas: 112 self, 0 foreign). Real leaks are few and localized: yemaya → {oya 10, aphrodite 10, uzume 8, maya 8, isis 8}, isis/3d-generation → @yemaya/_ (14) while yemaya/remote-film-capture → @isis/_ — a bidirectional domain couple that the declared constraint set (yemaya may depend on isis, not vice versa) appears not to permit; either the isis-side imports predate the rule or escape via untagged/allow-listed packages. Worth a targeted nx lint sweep of libs/isis/3d-generation.

H-2. Boundary governance erodes via exceptions: the eslint allow list accretes phase-commented package exemptions; apps/oshun/web is fully exempt; 451 projects are untagged (C-4). The mechanism is right; the enforcement perimeter needs closing.

H-3. Four BFFs share a name and nothing else.

BFF src .ts files Internal structure Middleware
apps/oshun/bff 1,987 routes/ + ~70 feature dirs rich (authz, entitlements, idempotency, abuse-protection + tests)
apps/lilith/bff 385 api/ and endpoints/ and routes/ and middleware/ — all four 2 files
apps/kalika/bff 9 flat files none
apps/urania/bff 0 only a stray node_modules/

There is no shared HTTP substrate: zero imports of any server/app factory lib from any BFF; CORS/auth/error handling are re-implemented (or absent) per app. Worse, @oshun/gateway is not an HTTP gateway at all — it is a Traefik infra-config CLI, so the obvious name for the missing shared layer is already taken by an unrelated tool.

H-6. Dead and hollow apps. apps/urania was fully dead: 0 source files, 0 project.json, 0 references repo-wide — and, on closer inspection during remediation, never even git-tracked (untracked empty scaffold dirs from 2026-05; removed from the working tree 2026-07-16 per R-4b). Hollow scaffolds: apps/v7 (10 source files), apps/infra (13), apps/cybele (16), apps/v8 (16), apps/v6 (19 — despite many sub-service dirs like egbe-clio-service), apps/neith-vault (20), apps/asase (32). And Nx coverage gaps: apps/psyche has 94 source files but a single project.json (apps/psyche/admin only), apps/euterpe-studio-web 423 source files / 1 project — code invisible to nx affected.

H-7. Backend layout vocabulary is unstandardized. The same concept is spelled routes/ (yemaya/api, oshun/bff), api/ (isis/web, lilith/bff), endpoints/ (lilith/bff), or ~130 feature dirs directly at src/ root (apps/lilith/svc-ai); deployable naming varies across bff, api, svc-*, api-gateway, worker.

H-4. Single-file libraries (F-6) defeat Nx's incremental-build value: a one-line change to a 28k-line index.ts invalidates the whole lib and every dependent, and tree-shaking can't help consumers.

H-5. Nine (now ten) products, three placement conventions (B-3) is the biggest architectural-navigation cost: "where does V code live" has three answers depending on N — and the newborn V10 (see §0 addendum) will make it four unless R-8 lands first.


4. Recommendations (prioritized)#

P0 execution log (2026-07-16):

  • R-5 done — dead @oshun/logger aliases removed; phantom poetry.lock/root-pyproject.toml/ruff.toml refs dropped from nx.json; yemaya studio-web storybook targets moved off the never-installed @storybook/angular executors; nx release scope verified and documented in C-8 (decision needed, not auto-fixed).
  • R-3 done — eight dead root scripts deleted; typedoc.kalika.jsonscripts/kalika/, lighthouse.config.js.github/ with all references updated. 54 root reports (including this one) moved to docs/audits/ after verifying zero inbound links and only intra-set outbound links; docs-center render + --verify green with the reports adopted as discipline docs. Kept at root: tooling-parsed reports (see meta-note) and active planning docs. TODOS.md retirement deferred — it is parsed by phase checkers and named in CLAUDE.md; needs its own repointing pass.
  • R-4 done (phase family) — 25 verify:phase-N npm scripts replaced by scripts/verify-phase.mjs dispatcher (pnpm verify:phase <n>); CI, the bellona composite gate, five self-wiring checkers, and doc call sites updated. The 403 verify:v3/v6/v7/v8 entries are live product gates wired into five workflows and 646 doc lines — deliberately deferred to the R-14 target-standardization work. Found in passing: phase 13/24/33/65 checkers fail on pre-existing repo drift (jest-junit pin, missing apps/oshun/web/src/middleware.ts, @nisaba mappings) — phase 65 runs in nisaba-ci.yml, so that gate was already red.
  • R-4b done (urania)apps/urania was untracked empty scaffold; removed from the working tree. Hollow-app decisions and psyche/euterpe Nx coverage remain open.
  • R-1 done — 6,147 artifact files untracked (~720 MB of pack weight): both SwiftPM .build/ trees, backups/ bundles, and Hardhat build-info/; gitignore rules added and a regex-based scripts/check-forbidden-paths.sh gate wired into the ci.yml quality job (verified against pre-purge HEAD). Contract ABIs stay tracked — they are runtime inputs (corrected A-4). History rewrite deferred: needs coordination across active worktrees.
  • R-2 done — 3,086 generated HTML files untracked (docs-center, md-twins across V1–V10/WALKTHROUGH×5/DOMAINS/docs/systems/platform, vdocs index + search index); verified renderer-owned via delete-and-rerender (100% regenerated by tools/render-docs-center.py). Pre-commit regen/re-stage block removed; vdocs-html-fresh.yml reworked from freshness-check to build + --verify + artifact upload; vdocs-reader-ui.yml now renders before testing; generated paths gitignored (with carve-outs for V2/web hand-written index.html pages and TypeDoc trees under docs/). Follow-up: the 540 TypeDoc API-reference pages under docs/domains/*/extras/generated/ are a separate generator and remain committed for now.

P0 — Repo health (mechanical, high payoff, do first)#

  • R-1. Purge committed artifacts. Remove from the index and ignore: **/.build/ (Swift), backups/*.bundle (relocate to S3/MinIO), apps/lilith/contracts/artifacts/, V6/ue/Plugins/VRM4U stray status noise (submodule bump hygiene). Add CI guard (a forbidden-paths check) so they can't return. Then schedule a history rewrite (git-filter-repo) or fresh clone-point to reclaim the ~850 MB pack — coordinate with all worktrees before rewriting.
  • R-2. Stop committing generated HTML. Render docs-center/vdocs/walkthrough HTML in CI (job exists: vdocs-html-fresh) and publish to Pages/artifact storage; delete the 3,815 tracked HTML files and the pre-commit regen step. This also fixes the recurring "post-commit regenerates 96 HTML files" and parallel-session merge-clobber traps.
  • R-3. Root cleanup. Move the 71 root reports into docs/audits/ (naming: YYYY-MM-DD-<slug>.md — the convention docs/audits already uses); delete the eight dead root scripts; move typedoc.kalika.json, lighthouse.config.js etc. next to their owners; retire TODOS.md (8 MB) in favor of the already-split TODOS/ dir.
  • R-4. Collapse verify:phase-*: one scripts/verify-phase.mjs <n> runner + delete 441 npm scripts and 25 of the 26 clones.
  • R-4b. Delete apps/urania (0 sources, 0 references) and decide each hollow scaffold app's fate (implement or remove; H-6). Bring apps/psyche/* and apps/euterpe-studio-web fully under Nx projects so affected sees them.
  • R-5. Fix config drift now: remove the 2 dead @oshun/logger aliases; fix or delete the phantom ruff.toml/pyproject.toml/poetry.lock refs in nx.json; verify/repair nx release.projects; remove the 2 @storybook/angular executors.

P1 execution log (2026-07-16):

  • R-10 done (foundation + pilot)@oshun/math, @oshun/ids, @oshun/collections, @oshun/resilience created (73 tests, all green; ULID spec-vector verified; injectable clocks/randomness). Pilot codemod (tools/codemods/adopt-shared-math.mjs) migrated 47 kuanyin files to @oshun/math with 1 conservative skip; all 13,438 kuanyin tests green. The fail-loud clamp immediately caught a real latent NaN in ncii-deepfake-protection (fixed at source). Remaining rollout: domain-by-domain via the codemod. Rewiring http-client/gpu-dispatcher internals onto @oshun/resilience is a follow-up (their retry APIs are HTTP-typed public surface).
    • Wave 2 (nous, 2026-07-16): 446 files migrated; codemod jsdoc-prefix regex bug found and fixed (lazy [^]*? docblock match swallowed unrelated functions — 3 collateral deletions restored, net-deletion audit now a standard gate); 11 conservative skips left for manual review.
    • Wave 3 (aphrodite, 2026-07-16): 497 files across 88 packages; zero collateral deletions; all 88 suites at/above HEAD baselines. Fail-loud clamp exposed 6 more latent NaN/∞ bugs (zero-duration transitions, Pearson 0/0, gravitational redshift 0×∞) — fixed at source. Side-payload: 73 dead-store lint errors fixed, one parameter-ignoring dead helper removed, the crowd-control queue's skipped effect-conflict check implemented with a symmetric-conflict test, 35 vestigial rootDir tsconfig entries removed (TS6059). 20 codemod skips left for manual review.
    • Wave 4 (isis, 2026-07-16): 282 files across 32 packages; zero collateral deletions; all 32 suites at/above HEAD baselines. Codemod import-anchor bug found and fixed (whole-file ^import [^;]+; regex crossed newlines and matched import lines inside embedded template-literal scripts, dropping one insert mid-class — all four waves audited, one occurrence). Repairs riding along: an invalid readonly indexed-access type that kept a quality-gates test file from ever collecting, a conflict-resolver test fixture with an invented connector shape, the benchmark embedding provider's fabricated clip-vit-base-patch32 modelId (now deterministic-feature-hash-v1), and 9 dead-store lint errors. 20 more skips for manual review.
    • Wave 5 (hathor, 2026-07-16): 248 hathor files + 9 straggler files from earlier waves; zero collateral deletions. New codemod shape for the default-range clamp(value, min = 0, max = 100) idiom — short call sites padded via balanced-delimiter scan, exported definitions never adopted. All 9 touched package suites at/above HEAD baselines; two pre-existing reds proven byte-identical at HEAD. gemini-physics-consequence-analyzer stays in the backlog (needs an isis seam, not a math migration).
    • Wave 6 (calliope, 2026-07-16): 69 calliope files + 6 isis stragglers; zero collateral. New const-arrow codemod shapes (plain 3-arg + a [0, 1] default-range variant). Calliope's ~155 clamp+quantize hybrids (Number(...toFixed(n)), Math.round, schema.parse) deliberately NOT migrated — different semantics; a shared clampQuantized helper is a follow-up design decision, not a mechanical dedup. The initial mass test failures were a stale gitignored @oshun/ai dist missing the openai-compatible subpath — rebuilt, all 16 packages green.
    • Wave 7 (yemaya, 2026-07-16): 171 yemaya files + 3 stragglers; zero collateral. New shapes: default-range function clamps, statement-form clamp01, and a clamp01-delegating shape gated on co-adoption. The 47 Number.isFinite-guarded fail-safe clamps stay local by design (shared clamp fails loud on NaN — a different contract). Critical codemod fix: padCallArgs applied edits in reverse match order, which breaks when a short call nests inside another short call — the outer insert landed 16 chars early, corrupting an adjacent Math.max (typechecks fine because Math.max is variadic; caught only by tests). Fixed with descending position sort + string/comment-aware scanning; a <3-arg-call corruption detector is now a standing wave gate, and the committed hathor/calliope waves audited clean against it.
    • Wave 8 (family helpers, 2026-07-16): the two dominant backlog families became first-class @oshun/math helpers with exact-semantics tests — clampRound(value, min, max, decimals) (Number(toFixed) rounding, fails loud) and clampFinite(value, min, max) (returns min on non-finite, the fail-safe contract). Codemod gained a generalized call transform (pad with the deleted definition's own defaults + append its decimals + rename), so call sites carry semantics explicitly. 184 files across calliope/yemaya/isis; all 20 touched package suites fully green.
    • Wave 9 (residue + seam, 2026-07-16, commit 32cd1ef5c2): 8 more shapes (statement clamps, fail-safe operand variants, required-args quantizers, lerp-with-clamped-t → shared lerpClamped); 68 files, 71 defs, zero collateral, 28 suites green. The 65 remaining skips are documented deliberate refusals (byte/int clamps, schema-parse, isFinite+round hybrids, exported transformed-call defs) — the DRY math rollout (R-10) is complete. gemini-physics-consequence-analyzer seamed off isis: it now declares the structural multimodal provider subset it uses (PhysicsVisionProvider) with required constructor injection; isis's GoogleProvider satisfies it structurally at composition roots. The last flagged cross-domain relative import is gone.
    • Ids wave (finding E, 2026-07-16): the id story is deliberately NOT a blind codemod — a fresh survey found 536 definitions across 219 distinct shapes, and unlike clamp they carry observable FORMATS (111 files parse ids with split('_'), deterministic content-hash makeIds, persisted entity ids). Executed: the format-identical crypto.randomUUID() wrapper family migrated to @oshun/ids uuid() (arete/balance, 7 files, 240 tests green), and a new oshun-stub/no-handrolled-ids WARN rule (with RuleTester coverage) points every new hand-rolled generator at @oshun/ids while grandfathering existing formats — those consolidate per-format-owner decision, not by lint pressure. Ride-along: the plugin's RuleTester harness had been silently broken since the eslint 10 upgrade (8.x parserOptions form) — fixed to flat-config languageOptions, all plugin rule tests actually run again.
    • Per-app env split (2026-07-16): tools/env/split-env-examples.mjs derives one .env.example per apps/<name> from the variables the app's own source directly references, grouped by the canonical file's owner sections (13 apps emitted, 21 with no canonical vars skipped). Root .env.example stays canonical; generated files carry a referenced-but-uncanonical section so drift surfaces instead of hiding. --check wired into the ci.yml quality job next to env-ownership.
    • Domain doc-set reconciliation (2026-07-16): the "editorial merge" of the 25 parallel domain doc sets is resolved by the docs-center's own shipped design, not by destructive merging — deep-dive/ is canonical (rendered, with a supporting-docs callout linking the operational tree); the missing piece was the reverse subordination. The 50 same-named architecture.md/features.md operational twins now carry a canonical -pointer header naming their deep-dive counterpart and their operational role, so neither reads as a second source of truth. Docs-center --verify integrity (3,432 entities) and generator pytest (27) green.
    • Root tara/ retired (2026-07-17): zero external consumers (only its own @module comments matched); the tree is the phase-22.1 declarative foundation (2,062 lines of app/content/feature/environment config plus placeholder content/assets), richer than — not superseded by — the consumed libs/tara/config. Moved intact to apps/tara/foundation/, README rewritten to explain the relationship, ^tara/ added to the retired-roots guard. Historical TODOS phase-22 path references left as record. tara suites green; per-app env example regenerated (the moved tree's env refs now surface in apps/tara/.env.example, as the sync gate requires).
    • services/ → apps/ re-gated (2026-07-17): scoping found services/ {metis,psyche,concordia} wired into deploy-ecs.yml, deploy-hetzner.yml, and infrastructure/terraform/variables.tf — container build contexts and deploy paths. Moving them without a deploy-verified window risks production deploys; the item moves to the owner-gated bucket alongside Terraform root unification.
    • Neith cargo umbrella (R-18/A-7, 2026-07-17, commit 767d22e879): the 462 pure workspace roots + 1 self-rooting package under libs/neith (92% of the repo's 505) consolidated into one umbrella: 599 member crates, one 300-entry merged catalog, one committed 816-package Cargo.lock. Merging is semantics-preserving — path entries normalized (most "conflicts" were vantage-point artifacts), caret-equivalent reqs unified, feature unions for equal reqs, genuine conflicts (thiserror 1/2, quick-xml 0.36–0.39) inlined into the 58 minority crates, the ten AGPL licenses inlined rather than homogenized, six zero-dependent package-name collisions parent-namespaced with lib target names kept. Cargo.lock global ignore removed (A-7); CI premerge planner roots → libs/neith (plan verified locally), 446 project.json cargo targets repointed, sccache manifest + four neith contract checkers pass. Verified: full-graph cargo metadata, sampled cargo check/test --locked across every override class.
    • Non-neith umbrellas (2026-07-17): generalized cargo-umbrella.py consolidated kalika (24 roots → 34 members), oya (3 → 23; Rust↔TS parity harness green 120/120 at 3.7e-15), and euterpe (2 → 6; dsp-core 219 tests); vault-crypto/native-memory folded into the neith umbrella. Deliberate refusals: the two yemaya-raster-gpu roots (documented standalone-by-design) and maya's two roots (already proper multi-crate workspaces; engine-core CI-coupled with known build fragility). Lib workspace roots 40 → 10, each now a deliberate unit.
    • Python hygiene (R-18 tail, 2026-07-17, commit ff34b4fec3): root ruff.toml from the measured consensus of the 48 existing configs (nearer configs still win — no project's lint behavior changes); poetry.lock un-gitignored; 57/59 PEP-621 projects locked with uv and 21/24 poetry projects locked. Locking surfaced real manifest debt fixed at source: jupyter-kernel's undeclared workspace-local kalika-sdk source, phase-89's unsatisfiable <3.14 claim and its seven pairwise- incompatible backend extras (full conflict matrix declared), voice-engine's httpx pin conflicting with the psyche platform. Documented refusals (5): nemo-rl and pytorch3d have no PyPI releases, zoomus ^0.1.15 never existed, psyche root inherits avatar-engine — those manifests never resolved from a clean environment; the locks make that visible. R-18 is complete.
    • BFF substrate, increment 1 (R-13c, 2026-07-17, commit a50331fefa): @oshun/bff-kit created from apps/oshun/bff's mature middleware — tracing, tenant context, authz, server-side idempotency + Redis store, abuse protection + Redis store, device integrity, residency guard (nine modules, shared-lib coupling only). The BFF's 1,081 middleware importers are untouched via exact named re-export shims. Behavior neutrality proven like-for-like: the 11 pre-existing failing test files fail identically (17/86) with originals restored and with shims; full suite 6,100 green. App-coupled middleware (entitlements→customer-auth-store, residency-routing→consent state) stays in-app with seams named for increment 2, as does adoption by lilith/kalika BFFs. @oshun/gateway renamed to @oshun/traefik-config (no code consumers; 15 tests green; docs re-rendered + verified) — the natural substrate name is free. Note: apps/oshun/bff tsconfig has noCheck: true, so its tsc is vacuous — the kit now real-typechecks the extracted modules.
    • Increment-1 corruption + increment 2 (2026-07-17): commit a50331fefa landed CORRUPTED — a failed lint-staged run left the kit sources replaced by self-referential shims, and re-running the shim generator against those produced comment-only shim files; the real middleware existed nowhere in the tree. Two sessions independently shipped restorations (a432f8f891 and this branch's fix, merged); the generator now asserts kit files are real and export lists non-empty. Increment 2 rode the fix: entitlements and residency-routing joined the kit behind fail-closed injected seams (BffSessionTierResolver, crossRegionConsentResolver); the oshun BFF wires its stores through its shims, preserving exact behavior. Middleware gates 29/29, kit suite green. Trap for the record: stale node_modules/.vite serves pre-corruption module content — clear it when middleware resolution misbehaves. Post-merge full BFF suite at the pre-existing 28-failure baseline. lilith and kalika BFFs adopted the substrate's request tracing (one validated x-correlation-id per request + structured completion logs — additive beside kalika's x-request-id and lilith's per-route correlation reads); both suites byte-identical to baseline (kalika 5/5; lilith 1,402 passing with its pre-existing 34 collection-error files unchanged). Deeper adoption (idempotency, abuse protection, authz) is per-app feature work needing each owner's stores/policies — the substrate is now available to all three BFFs.
    • Maya monoliths split (F-6, 2026-07-17, commit d824049021): the six maya index.ts god files (126,667 lines) split into 46 dependency-sound modules + barrels by tools/codemods/split-index-monolith.mjs — TS-API declaration graph, Tarjan SCC condensation (mutually-recursive decls share a module), topological packing with backward-only imports, and an asserted-identical public export surface. All six suites at exact baselines (804 tests); over-imports pruned via tsc's own TS6133 output. The F-6 remainder followed on 2026-07-17: the splitter grew a --file mode (header imports distributed per-module with relative paths rebased; modules dir named <stem>-modules to dodge the extensionless-resolution trap), and yemaya's 14,927-line game-pipeline.ts became 7 dependency-sound modules + an 11-line barrel — 232 public exports preserved, the export * as gamePipeline consumer untouched, yemaya/agents at its exact 15,258/15,258 baseline and tsc error-count identical to HEAD. Every named F-6 god file is now split or extracted.
    • Vitest-config dedup (R-14 slice, 2026-07-17, commit c29f1b4ab5): the top-4 hashes among the 2,657 per-project vitest configs were one semantic configuration in four spellings; two presets (configs/vitest/node-lib{,-coverage}.ts) now carry each class exactly and the 457 member files are one-line depth-correct re-exports — cwd discovery, Nx targets, and --config invocations untouched. Eight sampled suites green across every path depth + a --coverage smoke. Hashes 5–8 (~200 files) follow the same recipe when touched.
    • LFS correction + F-7 inventory (2026-07-17, commit bc1e1323ca): of 93 declared LFS patterns exactly one matching file was raw — V5/.../BootMap.umap, the perpetual-modified trap — converted via filter re-add (git lfs migrate refuses beside the untracked VRM4U dir), pointer pushed, status finally clean. The audit's 67MB .mdb blobs were already purged; the remaining large plain blobs (animation_catalog 12MB, seed-registry 11.5MB) match no pattern — LFS-tracking them is a policy decision coupled to CI lfs: true checkout settings, deferred explicitly. F-7: tools/audit/todo-burndown.mjs + docs/audits/TODO_BURNDOWN.md — 516 files / 1,272 markers (513 actionable; apps/aphrodite alone: 669 in 51 files), classified per owner surface, regenerable.
    • Burn-down slice 1 (2026-07-17): viewer shows.ts (30 markers, the top offender file) implemented for real against the prisma show domain through a ShowsStore seam — explicit escrow/refund charging model with atomic balance-guarded charges, lifecycle guards, and 501 model_gap for the schema-unmodeled features (advance tickets, reminders, per-viewer goal contributions). The integration spec's stub-coherent Shows sections (they asserted success for random ids) rewritten to seeded-store semantics; shows tests fully green, remaining 30 integration failures are the pre-existing Notifications/Settings scaffolds — the next slices. Markers 1,254 → 1,228.
    • Burn-down slice 2 (2026-07-17, commit 9db22cae2c): viewer settings + notifications implemented for real. New Notification/PushSubscription prisma models (migration 00002), ViewerSettingsStore + NotificationsStore (SQL + memory doubles), settings routes over the schema's real surface (profile, sensual-tier opt-in, preferred categories, notifications master switch) with 501 fail-loud for unmodeled display/security/account groups, notifications CRUD/bulk/push-registration with fail-loud test-send. Two real app.ts bugs fixed along the way: the auth middleware minted viewer-user-id from ANY bearer token (now HS256 JWT via VIEWER_JWT_SECRET, 503 fail-closed when unconfigured, verifier test seam), and the rate limiter keyed on a userId that is never set at its middleware position, so all callers shared one anonymous 100-req/min bucket — that exhaustion, not the scaffolds alone, produced the 30 "baseline" integration failures. Suite 138/138 (was 108/138). Markers 1,228 → 1,181.
    • Burn-down slice 3 (2026-07-17, commit d574766481): payment tips/payouts/subscriptions + broadcaster shows implemented for real. Payment: SqlTipsStore (transactional balance-guarded tip send, 20% fee split, goal progress, menus, leaderboards, bucketed stats), SqlPayoutsStore (token-debiting requests at the fixed 5¢/token creator rate, PENDING-only cancel+refund), SqlSubscriptionsStore (tier guards, price snapshots, calendar billing periods, cancelled-pair reactivation forced by the schema's viewer/broadcaster unique constraint, MRR/churn stats); unmodeled surfaces (payout methods/schedules/tax docs, perks, billing history) fail loud. Broadcaster: JWT auth middleware added (same fail-closed contract as viewer), shows routes settle real escrow — decline refunds, end bills minutes clamped to [minimum, escrowed] with 80% share, group shows refund entry fees on cancel; the scaffold's /goals/history route was shadowed by /goals/:goalId (registration-order bug) and its onError flattened HTTPExceptions to 500 (the pre-existing invalid-JSON failure) — both fixed. Suites: payment 109 passed (6 pre-existing earnings/webhooks failures remain), broadcaster 53/53 (was 35/36). Markers 1,181 → 1,078.
    • Burn-down slice 4 (2026-07-17, commit 86692c03df): payment earnings + webhooks implemented for real. EarningsStore derives every figure from the money-carrying rows (tips, ended shows, subscription billing-period starts, payouts) through shared pure compute functions so SQL and the memory double agree exactly: summary, per-source breakdown, daily/hourly series, derived ledger with payout debits, window-over-window analytics (incl. conversion from view_sessions), tip leaderboard, token milestones; freeform ledger credits + report files fail loud. The global /leaderboard literal was registered after /:userId and unreachable — the 6th pre-existing failure, same shadowing class as /goals/history. WebhooksStore executes verified provider events (purchase complete/fail/refund/reinstate keyed by provider payment reference, idempotent on replay; subscription renew/past-due/cancel with calendar period advancement; payout complete/fail with token refunds); internal worker callbacks now require an HMAC over the raw body (INTERNAL_WEBHOOK_SECRET, fail-closed) instead of accepting unsigned financial mutations, and purchase callbacks report the recorded state instead of assuming success. Spec sections rewritten with real Stripe/HMAC signatures, replay and clawback assertions. Payment suite fully green 120/120 (was 109/6). Markers 1,078 → 1,050.
    • Burn-down slice 5a — chat (2026-07-17, commit 27778d4c6b): chat service + viewer chat implemented for real, with NEW DirectMessage/UserBlock models (migration 00003) since DMs and user-level blocks had no tables. A chat room IS a stream (views derive from streams + live view-sessions + message counts); messages get real cursored history/search/soft-delete/stats — /search was shadowed by /:messageId (the 3 baseline failures, 4th shadowing instance); moderation bans are viewer_blocks rows with the log derived from blocks
      • deletions; DMs are pair-key conversations with bidirectional block enforcement, read receipts, and synchronous mass-DM fan-out; health probes run a real DB check; socket messages persist with authorship checks; viewer chat gets ban-gated sends, block-filtered history, EMOTE-persisted reactions, and whispers over direct_messages. Chat suite 50/50 (was 84/87); viewer 149/149. Markers 1,050 → 962.
    • Burn-down slice 5b — devices (2026-07-17, commit 3c951fe296): device routes implemented over the schema's real model — broadcaster-owned devices with a viewer-control policy. Broadcaster: registry CRUD, client-reported connection state, status summaries, FK-protected deletes; hardware commands/vendor pairing fail loud (device_bridge_not_configured). Viewer: commands record MANUAL device_controls rows clamped to the device policy with pattern validation; stop-all emits STOP controls for in-flight devices; viewer-owned hardware has no table and fails loud. Devices app's three dishonest comments replaced with the client-side-discovery truths. Viewer 158/158, broadcaster 60/60, devices 59/59. Markers 962 → 917.
    • Burn-down slice 6 (2026-07-17, commit e3999be8d4): payment tokens + transactions implemented for real. Tokens: the package catalog and 10-tokens/USD rate are load-bearing pricing constants — initiate records a PENDING token_purchases row priced from them and the session endpoint reports its true state; the old confirm endpoint minted tokens on client say-so and now fails loud pointing at the signed provider webhooks; viewer-to-viewer transfers are refused outright (no audit table — silent money movement), holds and platform-side token refunds fail loud with pointers to show escrow and the charge.refunded webhook. Transactions: the viewer's unified history derives from purchases/tips/show-participations/subscription periods (no transactions table) through shared compute functions — filtered listings, cross-table detail lookup, between/stream views, settled- only summaries and daily buckets, and a ledger of signed deltas against the live balance; /flagged was shadowed by /:userId (5th instance). Payment suite fully green 109/109. Markers 917 → 887.
    • Burn-down slice 7 (2026-07-17, commit c7e8fe34d7): streams (three services) + viewer history implemented for real. Streaming (media plane): the state machine validates against the ROW's stored status; ingest auth matches the presented stream key against the stored one — the scaffold accepted ANY non-empty key (same auth-fabrication class as the viewer JWT bug); stats report recorded columns and the session-derived device split; wire telemetry fails loud. Broadcaster: own-stream CRUD with status filtering, key rotation and return-nothing revocation, lifecycle guards with recorded stop stats, modeled device-integration settings, uploaded thumbnail URLs; playback/ingest URLs are stored provisioning results, never fabricated hosts. Viewer: browse/search/details/join enforce the sensual-tier opt-in; trending = viewers-per-minute-live and recommended = watched-category affinity (named heuristics); the category catalog derives from live streams; join records a ViewSession and leave closes it, crediting total_watch_time; VODs = public recordings, schedules real. History: session-backed with real privacy deletion, watch-time stats/favorites; watchlists point at follows, clips/screenshots fail loud. Suites: viewer 160/160, broadcaster 43/43, streaming 17/17. Markers 887 → 812.
    • Burn-down slice 8 (2026-07-17, commit 07ff6a7d50): broadcaster profile/settings/analytics implemented for real. Profile: the broadcaster's own row with strict patch validation; verification read-only (KYC intake fails loud); schedules are concrete stream_schedules entries, not the scaffold's unpersisted weekly-slots grid; followers/subscribers from the relations; the block list is viewer_blocks shared with chat moderation. Settings: the modeled surface is the monetization trio (tip_menu_enabled, token_per_minute, private_show_price); notification/privacy/stream-default groups fail loud, payout surfaces point at the payment service. Analytics: overview/streams/audience/engagement/realtime/compare derived from recorded rows via shared fact computes (new-vs-returning from first-seen timestamps, tip conversion = tippers/viewers, compare = doubled-window minus current); earnings point at the payment service, exports fail loud. Broadcaster suite 62/62. Markers 812 → 776.
    • Auth/CDN verification (2026-07-17): the auth and cdn apps were already fully implemented — not scaffolds. Auth has 0 markers and real PBKDF2/timingSafeEqual crypto; cdn has real HMAC signing + S3 presigned uploads behind an S3ClientLike seam. Both suites 26/26. No conversion work; the one OAuth Math.random() nonce is a prior documented CSPRNG carve-out, left in place.
    • Burn-down slice 9 — streaming sub-routes (2026-07-17, commit 34313560a3): the seven media-plane sub-routes rewritten so the schema-backed surface is real and media-infra fails loud. Ingest RTMP auth resolves the stream by stored key and gates on broadcaster status (accepted ANY key before — 4th auth-fabrication instance); on-publish/on-publish-done bridge to LIVE/ENDED. Discovery is a real search/browse catalog over streams+broadcasters (named sorts, isMature gating). Recording lists/gets/deletes completed VODs on the recordings table + storage usage. Distribution/thumbnails serve stored asset URLs; transcoding serves the fixed encoder ladder constant. WebRTC/CDN/DVR/ transcoding-jobs/QoE-telemetry fail loud (media_infrastructure_gap / observability_gap). Two new stores (MediaControlStore, StreamDiscoveryStore). Streaming suite 34/34. Markers 776 → 661.
    • Burn-down slice 10 — viewer following + tips (2026-07-17, commit 7674609758): following is real over the follows table (follow/unfollow maintaining follower_count, status, the two modeled notification columns, live subset); subscription READS real over subscriptions/subscription_tiers (active subs + monthly spend, a broadcaster's real tiers, detail); subscription WRITES → payment service. Tips: the money path is real — atomic balance-guard + 20% fee split + broadcaster credit + active-goal progress (same model the payment service uses); balance/history/goals/leaderboards real; the token catalog + purchase → payment service (the scaffold's prices CONTRADICTED the canonical ones). Virtual gifts, tip animations/sounds, goal-earmarked contributions fail loud. Two new stores (FollowingStore, ViewerTipsStore); integration spec Tips+Following rewritten. Viewer suite 142/142. Markers 661 → 618.
    • Admin/analytics slice 11 (2026-07-17, commit bc33bc070b): the admin, admin-bi-dashboard, and realtime-analytics apps were verified already-real (0 markers each, real aggregation/query services — no conversion work, reported like auth/cdn). The one genuine finding was the analytics dashboard service: ~15 fields returned fabricated zeros/empties behind // Would need additional calculation comments while the raw analytics event stream (queryEvents) carried the data. Now computed for real via a paged fetchEvents and seven exported, unit-tested aggregation helpers: earnings top tippers (from tip.received by tipper); viewer avg/total watch time + retention (viewers on ≥2 days) + returning (≥2 sessions) from viewer.watched; stream engagementRate (messages/viewer); tip median/amount-bucket distribution/hourly patterns/top triggers; follower sources (by referrer) + the absolute current total from the LIFETIME follower ledger (added − removed to window end) rather than a fabricated 0; peak hours (viewer/earnings/engagement) with scheduling recommendations; geography (viewers/tips/watch-time by country/city/ region); dashboard summary engagementRate + best stream + top tipper. New 10-test spec (the app previously had none); each assertion would FAIL against the old zeros. Analytics suite 10/10. This slice removes stub-lexicon fabrications rather than plain TODO markers, so the burn-down count is unchanged at 618.
    • Notifications delivery slice (2026-07-17, commit 908f7e64d9): the notifications app's queue processor fabricated delivery — deliverViaChannel returned true for every channel (// For now, simulate success), so a notification was marked sent when nothing was delivered, and the app-level email handler was a console.log no-op (// In production, would look up user email) while push failures were swallowed. Delivery is now real: NotificationService has a per-channel deliverer registry (registerDeliverer/hasDeliverer); deliverViaChannel awaits the registered transport and returns its actual accept/reject result (thrown errors flow to the existing retry/mark-failed path). in_app stays deliverable with no transport (already durably persisted + best-effort WS push); push/email/sms with no transport raise ChannelNotConfiguredError (a real failure) instead of fabricating success. app.ts wires a real push transport and, behind a resolveRecipientEmail seam, a real email transport (resolve address → SendGrid); with no resolver the email channel is left unconfigured and fails loud. Two new specs (the app had none for this): a service suite proving sent is only recorded on real acceptance, that rejects/unconfigured channels fail rather than fabricate, in_app via persistence+WS, and mixed-channel partial delivery; an app suite proving the email resolver seam + fail-loud default. Notifications suite 88/88. Lexicon-fabrication cleanup, so the TODO burn-down count is unchanged (the app had 0 TODO markers); the one remaining lexicon hit (email subject template substitution) is a signed-off stub:legitimate carve-out.
    • Socket layers (2026-07-17): the correct adversarial lexicon scan (an earlier per-dir scan used a PCRE lookahead that grep -E silently rejects, so it falsely reported zero everywhere) plus a read pass found real fabrications. Four slices landed:
      • Chat socket auth (759616831d): the server trusted the client-authored handshake for identity AND roles (handleConnection read handshake.auth.userId; socket.data.roles = handshake.auth.roles), so any client could claim any identity and grant itself moderation via the isModerator/isRoomOwner TODO stubs. New socket/auth.ts verifies an HMAC-signed token (signSocketToken/createHmacTokenVerifier, constant- time) in an io.use middleware; identity comes only from signed claims; fails closed with no CHAT_SOCKET_TOKEN_SECRET. 13 tests.
      • Chat DM persistence (7e96cf1aff): dm.ts kept its own in-memory Maps, so socket DMs were invisible to the HTTP /conversations view (the real dmStore) and lost on restart, and the list handlers abused dm_error code SUCCESS to return data. Rewired to the shared dmStore (pairKey = conversationId); real block enforcement; two new typed events. 5 tests.
      • Chat clear-chat (dfc322fa62): mod_clear_chat announced chat_cleared behind // TODO: Clear messages from database — a fabricated clear. Added a real ChatMessagesStore.clearRoom bulk soft-delete and wired it. The mute/slow-mode maps are honestly relabeled stub:legitimate per-node ephemeral state (a horizontal-scaling concern like the socket.io Redis adapter, not a fabrication). 3 tests.
      • Device gateway auth (4616492759): extractUserId returned handshake.query.userId ?? handshake.auth.token unverified, so any client could drive any user's intimate hardware. New websocket/auth.ts verifies a signed token (envelope matches chat's, so one gateway secret serves both); DeviceSessionManager fails closed without DEVICE_SOCKET_TOKEN_SECRET. 7 tests.
      • VR socket auth + verifier consolidation (60f5127db1): the vr playback ws trusted data.userId from the session:start payload, so a client could start a session as anyone. Rather than add a third verifier copy, the signed-token envelope was consolidated into @aphrodite/core (signSocketToken/createSocketTokenVerifier/resolveSocketTokenVerifier — one envelope so a single gateway secret serves all three services); chat and devices now re-export the shared primitives (~90 lines of duplicated crypto removed each), and vr verifies the handshake token on connect and uses the signed userId (dropping userId from the event payload). Core tagged type:lib/scope:aphrodite so the apps may depend on it (needed nx reset for the boundary rule to see it); the rootDir override was removed from the devices/vr tsconfigs to avoid TS6059 on core-source types. Core 421, chat 71, devices 66, vr 4 (new).
      • Notification ws auth middleware (a5e3c4e45e): the notification ws read socket.data.userId to authorize every operation, but no middleware ever populated it, so all operations failed "Not authenticated" (fail-closed, honest gap). createNotificationHandler now installs an io.use handshake middleware on the shared @aphrodite/core verifier (local websocket/auth.ts, NOTIFICATIONS_SOCKET_TOKEN_SECRET): it verifies the signed token and sets socket.data.userId from the claim; a missing/invalid token or no verifier rejects the connection. New 6-test spec (the ws layer had none); rootDir dropped from the tsconfig. Notifications 94/94. All five aphrodite realtime socket layers (chat, devices, vr, notifications; analytics-dashboard/realtime-analytics were already clean) now verify identity from the shared signed-token verifier — no client-trusted identity remains in the socket layers.
    • Health-check dependency probes (9e31c12ee4): the readiness/detailed health endpoints across six aphrodite services fabricated dependency health — hardcoded 'healthy'/true/ok behind // TODO: actual db check / // In production, ping ..., so a load balancer was told the service was ready even with its database down; analytics-dashboard /detailed dressed up abhHash-derived fake latency/hitRate/connection/ request metrics as real component health (mislabeled stub:legitimate). Fixed: payment, broadcaster, viewer and streaming run a real checkDatabaseHealth() probe (from @aphrodite/database, already a dep) and gate readiness on it — /ready now returns 503 when the DB is down instead of a fabricated 200 (payment /ready previously returned ready:true unconditionally). Deps these routes hold no client for (redis, kafka, MediaSoup/transcoding pools, payment processor, cdn/S3) are reported honestly as not_checked and excluded from the gate rather than faked; streaming /stats returns null (not zero) for un-measured live-plane counters; analytics-dashboard/cdn report not_checked with real process stats only. New health.spec.ts per service (16 tests; these routes had none) assert readiness reflects the real probe. Three pre-existing integration tests asserted the old always-200 /ready and were updated to stub checkDatabaseHealth healthy (partial mock, stores stay real). The eight other aphrodite health routes were verified already real (service.isHealthy, real redis.ping/cache round-trips, chat's real DB probe from slice 5) or liveness-only.
    • Alerts abhHash fabrication (339dcd7bfd): analytics-dashboard/alerts.ts used an FNV-1a abhHash to fabricate computed-looking data in four endpoints — alert history/active alerts, segment members (spending/watch- time metrics fed to the real fit model), funnel analysis (user counts, conversion rates). The app has no alert store and no event warehouse (only a logger, in-memory cache, two scoring models). These now fail loud (501 analytics_source_not_configured via a shared sourceNotConfigured helper); abhHash removed from the file; the real fit/quality models untouched. 4-test spec. Suite 73/73.
  • P0 DONE — analytics-dashboard warehouse build. abhHash (FNV-1a, a per-file copy) fabricated EVERY data route — dashboards.ts (38 sites), viewers.ts (36), engagement.ts (53), revenue.ts (37), exports.ts (25), trends.ts (37), predictions.ts (29) — ~255 sites across ~5,480 LOC, with ZERO real data client. Investigation found the "real analytics source" I'd pointed at does not exist: the analytics app is InMemoryAnalyticsClient-only, the analytics-core dashboard services have only Mock repos, and there are no analytics tables. User chose to BUILD THE WAREHOUSE. Progress:
    • Foundation (651725d647): real analytics_events table (Prisma model + migration 00004) and new lib @aphrodite/analytics-warehouse — app-flavored analytics types + IAnalyticsClient, a real SqlAnalyticsClient over @aphrodite/database (parameterized queryEvents with WHERE/ORDER/LIMIT+ COUNT; date_trunc('day') GROUP BY metric aggregations; jsonb INSERT) and a MemoryAnalyticsClient test double. 9 tests; SQL adversarially verified real.
    • Context wiring + revenue routes (170295091c): getContext exposes ctx.analyticsClient (real Sql default; setAnalyticsClient test seam; dashboard's unused app→app @aphrodite/analytics dep replaced by the lib). revenue.ts fully de-fabricated: /overview, /by-source, /transactions, /platform, /subscriptions, /creators earnings compute REAL aggregates over the event store via a paged fetchEvents (sum by source, per-day trend, distinct payers, fee = gross*0.2); /projections fails loud (501, no forecast model); tokens/gifts/upgrades = 0 (no event type, never faked). 5-test spec asserts real computed values. suite 78/78.
    • All 7 route files wired (revenue 170295091c, exports 2e145891ed, viewers c65ef3f9af, engagement cd8998cfe9, dashboards 9f5c356928, trends 7de1250720, predictions 3e9cb804ab): every abhHash route now aggregates the real event store via the shared fetchEvents pager, or fails loud where the shape has no source. Fail-loud (501 analytics_source_not_configured): all forecast/ projection endpoints, trends /anomalies + /insights (fake "ARIMA"/"Isolation Forest" model-name strings deleted), viewers /behavior + /cohorts, engagement /devices, export-job + scheduled-report + dashboard-layout lifecycles. Honest zero/empty/null for un-sourced sub-fields (systemHealth, goals, alerts, recommendations, byLanguage, OS, avgConcurrent, brand/model). predictions.ts feeds the REAL @sophia/predictions models real event-store history (not fabricated inputs). 43 new tests across 7 route specs, each asserting real values that FAIL against the old hash. No abhHash/Math.random /generate* remains anywhere in the app; suite 112/112 (was 69).
    • Ingestion producer (c81fba16eb): backfillAnalyticsEvents/runBackfill in the warehouse lib — a real, idempotent ETL that derives analytics_events from the existing aphrodite domain tables: tips→tip.received, follows→ follower.added, subscriptions→subscription.created (+ .cancelled when cancelled_at), chat_messages→message.sent, view_sessions→viewer.joined (+ viewer.watched when duration>0). Deterministic ids from source PKs + INSERT ... ON CONFLICT (id) DO NOTHING, so re-running never duplicates and a scheduled run with since is a continuous incremental sync. 9 tests over a fake db; lib 18/18. The loop is now end-to-end real: domain tables → backfill producer → analytics_events → SqlAnalyticsClient → the 7 wired dashboard routes. analytics-dashboard P0 fabrication is fully remediated. (The BFF events-ingest is a separate client-telemetry surface with GDPR erasure, not this warehouse's producer.)
    • Forward producer (eb34367b43): the analytics app's createApp now defaults its client to the real SqlAnalyticsClient (was hardcoded InMemory), so POST /api/v1/events(/track) persists to analytics_events — a live forward producer alongside the backfill. AppConfig.analyticsClient is the test seam; aligned the app's unused IAnalyticsClient query/execute to unknown[] for structural assignability; dropped the app tsconfig rootDir to avoid TS6059. app.spec.ts proves POST→queryEvents round-trips a real event; 11/11. The warehouse now has BOTH producers: historical backfill + live ingest.
  • R-12 done (tags + neith constraint) — all 451 untagged projects tagged scope:<domain> (446 neith + 3 aphrodite + 1 iris + 1 yemaya, JSON-validated); new scope:neith depConstraint (allows shared, contracts, neith, and the typed @nous LLM-provider seam used by crash-intelligence). Untagged-project escape hatch is closed; no wildcard constraint added (Nx semantics make a useful one equivalent to enumerating every scope). apps/oshun/web re-enable and the isis↔yemaya edge remain open — both need violation-fix budgets.
  • R-6 partial (evidence-corrected) — the audit's B-2 had the canonical tree wrong: infrastructure/terraform (not infra/terraform) owns the V1 state backends per its own deprecation notes and deploy-ecs.yml. Executed: deploy/terraform (legacy EKS-era tree, deprecated 2026-07-04) deleted after relocating its one live module (modules/github-oidcinfra/terraform/modules/, consumer source updated); infra/README.md added as the authoritative live-tree map with the single-root target layout. Physical unification of the three live roots needs a deploy-verified window (terraform plan + workflow working-directory updates in one change).
  • R-9 partialclients/demeter-pythonsdks/ (zero references) and integrations/neith-vaultinfra/neith-vault (one spec path updated), dissolving both single-entry roots. Deferred with reasons: services/{concordia,metis,psyche}apps/ touches 118 tsconfig aliases + 5 deploy-critical workflows (psyche is in the ECS/Hetzner paths); root tara/ is live shared config wired into the mobile/web builds (metro/jest/tsconfig relative paths).
  • R-7/R-8 scoped, not executed — renderer coupling measured at just 6 tools/docs_center files + 1 workflow filter (cheap to repoint), but the walkthrough/DOMAINS trees are actively written by parallel sessions today and V-tree moves invalidate 93 workflows' path filters; executing these mid-flight invites the documented merge-clobber failure mode. Concrete staged plan recorded in R-7/R-8 below; both need a quiet window and a single dedicated change each.

P1 — Structure consolidation#

  • R-6. One infrastructure root. Adopt infra/ as canonical (it holds the active ECS/Fargate terraform); fold infrastructure/* and deploy/* into it (infra/terraform, infra/helm, infra/k8s, infra/compose, infra/releases); leave a README tombstone in each old path for one release. Delete the already-DEPRECATED trees after migration.
  • R-7. One documentation tree. docs/ becomes canonical source (md only): docs/products/v1..v9/ (from V*/md), docs/domains/ (merge DOMAINS/ + systems/ + platform/), docs/walkthroughs/ (5 WALKTHROUGH dirs), docs/audits/ (root reports). docs-center becomes a *renderer* that reads docs/, not a second content store.
  • R-8. Pick one home per product. Recommended target: products/v<N>/{ue,services,web,libs,docs} (or the equivalent under apps/+libs/ if UE trees must stay at root for path-length reasons — then at least make V2/V4/V5 follow the V3 split so there is exactly one convention). Update the 56 v4 workflows' path filters as part of R-13.
  • R-9. Dissolve ambiguity dirs: merge services/* into apps/ (concordia/metis/psyche), clients/demeter-python and sdks/* into a single sdks/ with a README, integrations/neith-vault next to its app, tara/ assets into apps/tara. apps/infratools/ or infra/.

P1 — DRY closure#

  • R-10. Create the missing bottom layer: @oshun/math (clamp/lerp/…), @oshun/ids, @oshun/resilience (retry+backoff+sleep+circuit-breaker — fold the 4 shared-internal copies first so there is exactly one target), @oshun/collections (chunk/deepClone/deepMerge). Then codemod: the clamp signature is byte-identical in 1,234 files — this is a scripted find&replace plus import insertion, doable domain-by-domain with nx affected verification.
  • R-11. Finish the shared-lib migrations (logging, http-client, database, cache, config) and enforce with lint: ban from 'pino', new Pool(, new Redis(, and direct process.env outside libs/shared via no-restricted-imports/no-restricted-syntax (allow-list the 596 existing sites via one-time inline disables to ratchet, or migrate per-domain).
  • R-12. Close the boundary perimeter: tag the 451 untagged projects (scripted from path), add a catch-all depConstraint (sourceTag: '*' → explicit), re-enable boundaries for apps/oshun/web, and resolve the isis↔yemaya bidirectional edge (extract the shared media-pipeline types into contracts).

P2 execution log (2026-07-16):

  • R-13 done (workflow collapse) — the 51 foldable v4-* gates now live in V4/.ci/gates-manifest.json (filters + commands lifted verbatim, round-trip validated: 996 filters, 154 commands, 0 mismatches) behind one v4-gates.yml (diff-driven slug matrix via git :(glob) pathspecs, fail-open detection). 5 structural members kept standalone. 24 validator/JSON references repointed to the manifest. Verified: detector correct on real ranges, two gates green end-to-end, @v4/scripts suite 190/191 (1 pre-existing todo-signoff failure). Workflow count 148 → 99. Branch protection may need check-name updates.
  • R-13a done (node SSOT) — every direct setup-node pin (21× node-24, 9× node-22) now uses node-version-file: .nvmrc. Two G-2b corrections: the a11y nightly schedule is deliberately disabled (documented COST(pre-launch) rationale), and the 10 composite-setup holdouts are lightweight jobs that would regress if forced through the full pnpm install — they keep setup-node.
  • R-16 partial — commitlint scope-enum expanded from 22 to all 48 domains + v1–v10 + cross-cutting scopes (warning-level until the R-19 registry can generate it). Test-suffix enforcement deferred to the codemod rollout.
  • R-17 partial (evidence-corrected) — sanctioned-framework and overlapping-dependency policy written (docs/conventions/server-frameworks-and-deps.md). The audit's "remove bcryptjs/crypto-js" was wrong as a mechanical action: crypto-js is load-bearing for React Native encryption-at-rest (Hermes has no node:crypto; on-device ciphertext must stay decryptable) and bcryptjsbcrypt adds native compilation to six auth services' container builds — both need per-service migrations, now documented in the policy.
  • R-13b corrected, deferred — the scripts/isis/generate-v2-* fleet is not thin shims: median 578 lines each (585K lines total) of embedded per-artifact data over shared utils. Collapsing it is a data-extraction refactor with artifact byte-comparison, not a sweep.
  • R-14 correctedparallel: 3 stays: the dev box has 4 cores/15 GB shared across many worktrees and CI runners are 2–4 core; the audit's "raise it" assumed hardware this repo doesn't run on. Target-shape standardization (6,447 run-commands) remains the follow-up.
  • R-15/R-18 deferred with evidence — decorator-flag scoping and noUncheckedIndexedAccess need graph-wide typecheck budgets; a root ruff.toml would change lint results for the majority of the 83 Python projects that today rely on ruff defaults (only ~30% embed [tool.ruff]), so it ships with the per-project verification window, not before.

P2 — Build/CI/conventions#

  • R-13. Collapse workflow clones. One reusable product-gate.yml (workflow_call with slug+paths inputs) or a generator that emits them from a JSON manifest; target ≤60 workflows total. Move the four Isis gates in ci.yml into project targets. Fix trigger drift: give a11y-pa11y-nightly and v4-nightly-feel-tests their missing schedule: (or rename them), align the 21 Node-24 jobs with .nvmrc/engines (22), and migrate the 10 hold-out workflows onto ./.github/actions/setup.
  • R-13b. Consolidate scripts/tools. Fold scripts/docs/* into the canonical tools/ docs pipeline (one renderer); replace the 1,088 scripts/isis/generate-v2-* per-artifact files with one parameterized generator + a manifest; adopt tools/generators/* (Nx generators) as the only scaffolding mechanism.
  • R-13c. Build a BFF substrate (@oshun/bff-kit or similar: fastify app factory, auth/authz middleware, CORS, idempotency, error envelope — extracted from apps/oshun/bff's mature middleware) and rename @oshun/gateway (Traefik CLI) to @oshun/traefik-config to free the name.
  • R-14. Standardize project targets. Adopt Nx plugin inference (@nx/vite, @nx/eslint, custom cargo/pytest plugins) or one generator template; codemod the 6,447 run-commands variants down to a handful of shapes; delete per-project vitest configs where the preset suffices (top-8 hashes already cover ~700 identical files). Raise parallel, and evaluate self-hosted Nx remote cache for the fleet of worktrees.
  • R-15. One tsconfig preset chain: make configs/tsconfig/* the only extension point (base → node/react/service/library), remove redundant per-lib re-declarations, add noUncheckedIndexedAccess to base, and scope decorator options to the 16 Nest packages.
  • R-16. Conventions: one test-file suffix (.spec.ts) + placement (colocated) enforced by lint; commitlint scope-enum generated from the domain registry (error-level); README template per lib (one paragraph + owner + links) generated from systems/*.md as a starting point.
  • R-17. Dependency diet: remove bcryptjs, crypto-js, axios/node-fetch (route through @oshun/http-client); pick uuid or nanoid per use-case policy; document fastify (services) + hono (edge/BFF) as the only two sanctioned server frameworks, freeze express/Nest for new code.
  • R-18. Rust & Python hygiene: per-domain umbrella Cargo workspaces with [workspace.dependencies] catalogs; un-ignore and commit Cargo.lock for all binary/service workspaces; add root ruff.toml + adopt uv with committed lockfiles for the 83 Python projects.

P3 execution log (2026-07-16):

  • R-19 donedomains.json registry (58 entries: purpose extracted from the systems/ deep-dives, npm scope, scope tag, paths, project counts, owner, status). commitlint.config.js reads it at load time; .github/CODEOWNERS is generated from it (correction: a CODEOWNERS already existed but assigned @oshun/* teams, impossible on a user-owned repo — every rule was inert); tools/domains/check-registry.mjs runs in the CI quality job and immediately surfaced 9 in-use non-domain scope tags, now tracked as declared retag debt (legacyScopes).
  • R-21 doneARCHITECTURE.md rewritten from the measured 2026-07-16 state (domain matrix generated from the registry; phase-14 checker's required phrases preserved, failure set byte-identical before/after — its remaining failures are pre-existing missing libs/openapi doc bundles that never existed in any commit). docs/audits/README.md indexes all 60 archived reports.
  • R-20 pilot done (datasets) — the two dataset god-files extracted to JSON data files with typed re-export shims: kalika anomalous-data.ts (54,156 lines → 17 + 1.4 MB anomalous-data.tables.json; 648 tests green, exact values verified) and nisaba character-database.ts (25,508 → 85 lines + character-database.entries.json; 8,231 tests green, lookups exact). Trap for the rollout: name the JSON differently from the module — extensionless imports become resolver-ambiguous otherwise. The maya index.ts monoliths (28k/25k/22k lines) are code, not data — each needs a module-boundary design pass, deferred.
  • R-12 closed (dedicated-window session, 2026-07-16) — the isis→yemaya edge dissolved: the fourteen isis/3d-generation imports were generic utilities (typed event emitter + console logger) living in @yemaya/core; they moved verbatim to a new @oshun/events foundation lib, @yemaya/core re-exports (486 tests green), isis repointed (55 tests green, zero @yemaya imports remain). And the apps/oshun/web boundary opt-out proved obsolete: with it removed, a full boundary lint reports zero violations — only 24 stale eslint-disable directives, now stripped. No blanket boundary opt-outs remain in the workspace.
  • verify-fleet migration COMPLETED per-family (dedicated-window sessions, 2026-07-16) — after a first mechanical attempt was reverted (384 gate scripts self-assert their npm wiring), all four families were migrated deliberately with full-fleet baseline diffing: v7 (3 gates) and v8 (1) as the pattern prover, then v6 (129 gates, 989 wiring reference lines, four transformer rounds + five hand-migrated gates) and v3 (270 gates, one uniform transformer + seven hand-anchored variants). Every family re-ran against its pre-migration baseline with ZERO pass/fail flips: v6 keeps its 5 pre-existing reds, v3 its 27. All gates now run through scripts/verify.mjs + scripts/verify-manifest.json; root package.json is down from 549 scripts at audit time to 128.
  • R-22 deferred with plan — splitting .env.example (388 vars) requires per-var ownership analysis (grep-based assignment mis-labels shared vars) and the docs-center env page parses the root file; execute as: analysis script → per-app .env.example files → root file becomes the generated aggregate → renderer repointed, all in one change.

R-7 re-scoped on evidence (dedicated-window session, 2026-07-16): the five *_WALKTHROUGH/ trees are not documentation sprawl and must not be moved: they are a machine-integrated evidence pipeline — ~700 code files reference them, including the entire apps/oshun/web/e2e suite (which writes journey evidence into them), the playwright configs, and the mobile/web route-parity contract tests that parse them. Verifying a move requires the full e2e run against the live app, which no consolidation window on this box can provide. Finding B-4 is corrected accordingly. The genuinely movable R-7 remainder, with named consumers to repoint: systems/ (phase-8/65 checkers + 4 tools/docs_center files), platform/ (phase-98 checker + v6 privileged-access/DSAR gates), and DOMAINS/ (renderer domains/coverage/platform modules, scripts/docs/verify-domains-source-of-truth.mjs, render-domain-docs.py, reader spec — plus relative-link depth rewrites in 326 files). Each is locally verifiable via the renderer gates + the v6 gate fleet, and each is a single dedicated change.

P3 — Longer-term architecture#

  • R-19. Domain registry as code: one domains.json (name, purpose, owner, scope tag, npm scope, docs link, status) — generate commitlint scopes, CODEOWNERS, DOMAINS.md, and the boundary-tag lint from it. Add CODEOWNERS (none exists today).
  • R-20. Split god files: budget-driven refactor of the 10 largest source files (move datasets to .json/binary assets loaded at runtime or build step; split maya index.ts monoliths into modules with an index barrel).
  • R-21. Refresh ARCHITECTURE.md (or replace with a generated overview from the domain registry + Nx graph export) and mark the 60+ historical root reports as archived in their new docs/audits/ home.
  • R-22. Env config ownership: split .env.example per app with a generated aggregate; pair with @oshun/config schema adoption (R-11) so every var has a typed owner.

5. Suggested target top-level layout#

text
/
├── apps/            # all deployables (absorbs services/, flat naming: <domain>-<surface> or <domain>/<surface> — pick ONE)
├── libs/            # domain + shared libraries (unchanged concept)
├── products/        # V1–V9 product trees (ue/, content/, docs/ per product)  [or keep V*/ but make all nine follow one internal convention]
├── infra/           # terraform, helm, k8s, compose, releases (absorbs infrastructure/, deploy/, docker/)
├── tools/           # durable repo tooling (absorbs scripts/ one-offs after pruning)
├── docs/            # ALL markdown documentation (audits/, products/, domains/, walkthroughs/, adr/, runbooks/)
├── sdks/            # external-facing SDKs (absorbs clients/, integrations/)
├── testing/         # shared test infra (fixtures, e2e harnesses; absorbs tests/)
└── [configs at root: nx.json, pnpm-workspace.yaml, tsconfig.base.json→configs/tsconfig, eslint.config.js (thin), .github/]

Everything else currently at root (WALKTHROUGH*, DOMAINS/, systems/, platform/, TODOS.md, 71 reports, vdocs-*, backups/, stray *.ts) either moves into one of the eight buckets or leaves git.


6. Appendix — raw measurements#

  • Tracked files by top dir: libs 78,348 · apps 28,538 · V2 6,448 · docs 6,241 · V4 3,053 · scripts 2,909 · V5 2,122 · WALKTHROUGH 1,713 · services 1,325 · V3 705 · deploy 423 · V6 364 · DOMAINS 326 · infra 318 · docs-center 314 · testing 281 · docker 253 · TODOS 247 · V1 199 · tools 165 · .github 155.
  • Artifact weight: Swift .build/ 576.6 MB (6,140 files) · HTML 130.7 MB (3,815 files; 2,768 md-twins) · backups 119.3 MB · Hardhat 24.1 MB.
  • Executors: run-commands 6,447 · eslint 1,646 · vite:test 1,512 · js:tsc 1,170 · esbuild 148 · js:node 34 · vitest 33 · run-script 27 · jest 2 · angular-storybook 2.
  • Test files: colocated spec 9,834 · colocated test 5,286 · tests 1,178 · libs tests/ 364. jest packages 16 · vitest packages 2,100.
  • Server frameworks (package.json occurrences): fastify 114 · hono 67 · express 19 · @nestjs/core 16. Next apps 26 · Expo/RN app.json 71.
  • Workflows: 148 total · v4-_ 56 · v2-_ 7 · iris-* 7 · schedule-trigger 8 · dispatch-only 16 · workflow_call 1 · composite-setup users 112 (10 bypass) · node-24 pins 21 vs node-22 pins 10 · YAML LOC 27,736 · V#-targeting 93 vs apps-targeting 47 · stale path filters 1 (v3-workspace.yml).
  • scripts/: 2,909 files — isis 2,256 (1,088 generate-v2-*) · v3 274 · lilith 140 · v6 129 · audit 23 · root 43 (26 verify-phase-*).
  • BFF divergence: oshun 1,987 src ts · lilith 385 · kalika 9 · urania 0 (dead app).
  • Cross-domain import leaks (non-self, non-shared): yemaya→oya 10, yemaya→aphrodite 10, isis→yemaya 14, yemaya→isis 8, psyche→isis 4, psyche→iris 4, sophia→kalika 2, hathor→neith 7, aphrodite→aja 6.
  • pnpm: catalog refs 8,803 · pinned semver in workspace manifests 4,252 · catalog entries ~350.
  • Rust: Cargo.toml 1,437 · workspace roots 505 · tracked Cargo.lock 64 (globally gitignored at .gitignore:288).
  • eslint.config.js 1,638 lines · depConstraints 44 · allow-list ~15 · untagged projects 451 (446 neith).
  • tsconfig.base.json 172 KB · 2,164 aliases · 2 dead · preset users (configs/tsconfig) 83 files.
  • Root: 113 tracked files · 71 md reports · TODOS.md 7.7 MB · .env.example 388 vars · package.json 549 scripts (441 verify:phase).

7. Final reconciliation ledger (2026-07-18)#

Every finding and recommendation adjudicated: done (executed and verified in-tree on 2026-07-18), corrected (the audit's premise was wrong — the correction is the resolution), or deferred (an explicit, owner-gated decision with the reason recorded — not an omission). Verification for this ledger re-checked the tree directly (paths, configs, CI wiring), not just the execution logs above.

Finding Status
A-1/A-2 Swift builds, backups Done (R-1: 6,147 files untracked; scripts/check-forbidden-paths.sh guards in ci quality job)
A-3 generated HTML Done (R-2: 3,086 untracked; hook regen removed; vdocs-html-fresh.yml builds+verifies; docs/audits/*.html confirmed untracked 2026-07-18)
A-4 Hardhat artifacts Done, corrected (ABIs are svc-blockchain runtime inputs and stay; only build-info purged)
A-5 root landfill Done (54 reports → docs/audits; dead scripts deleted; TODOS.md a pointer; 19 root .md remain = tooling-parsed + active ledgers, incl. DOCS_CENTER_PAGE_AUDIT which self-declares in-flight)
A-6 LFS unused Done for the one raw pattern-match (BootMap.umap via filter re-add). animation_catalog/seed-registry match no declared pattern — LFS-ing them is a policy + CI lfs:true coupling decision, deferred explicitly
A-7 Cargo.lock contradiction Done (global ignore removed; umbrella lock committed; sampled cargo check --locked green)
A-8 stale top docs Done for ARCHITECTURE.md (rewritten from measured state, R-21). DEPENDENCIES.md / RESPONSIBILITY_SPLIT stay at root as tooling-parsed archives — archived-in-place, indexed as such
B-1 top-level concept mix Substantially done via R-3/R-7/R-9 (systems/platform/DOMAINS/tara/clients/integrations/backups dissolved). Remainder rides B-5 and B-3 below
B-2 four infra dirs Partial, corrected (canonical tree is infrastructure/terraform, not infra; legacy deploy/terraform deleted; infra/README.md is the live map). Physical single-root unification is deploy-gated — needs a terraform-plan-verified window
B-3/H-5 product placement Deferred with plan (R-8): V-tree moves invalidate 93 workflows' path filters; single dedicated change in a quiet window. V10 is the designated first adopter
B-4 8+ docs surfaces Done, corrected (walkthrough trees are a machine evidence pipeline — must not move; systems/, platform/, DOMAINS/ moved under docs/; docs-center is the renderer; docs/audits README indexes reports)
B-5 services/ vs apps/ Deferred, owner-gated: services/{metis,psyche,concordia} are wired into deploy-ecs.yml, deploy-hetzner.yml, terraform variables — moving without a deploy-verified window risks production
B-6 naming variance Done where mechanical (SCREAMING doc dirs gone; urania gone; orphan libs/tsconfig.test.json deleted 2026-07-18 after a zero-reference check). Flat-vs-nested app naming folds into the R-8 decision
C-1 hand-rolled targets Deferred as R-14 follow-up; first slice done (top-4 vitest-config hashes → 2 presets, 457 files)
C-2 parallel:3 Corrected — stays (4-core box shared by worktrees; CI runners 2–4 core)
C-3 named-input phantoms Done (phantom refs removed; root ruff.toml now real via R-18 python hygiene)
C-4/H-2 boundary perimeter Done (R-12: 451 projects tagged, scope:neith constraint, apps/oshun/web opt-out removed with zero violations, legacy scopes retagged; registry check in CI)
C-5/R-15 tsconfig presets Deferred with evidence: graph-wide typecheck budget required; noUncheckedIndexedAccess proven viable only in mobile so far
C-6 tsconfig.base contention Dead aliases removed (R-5). The 2,164-alias sharedGlobals invalidation cost is accepted — no cheap fix short of Nx ts-project-references migration
C-7 lint-plugin excludes Recorded as R-14 follow-up (target standardization decides what's linted where)
C-8 release config Done 2026-07-18: ADR-0073 — nx release owns releases (it is what release.yml runs); dormant changesets scripts + devDep removed; root-level-only scope documented as deliberate
D-2 overlapping deps Done via policy + corrections (crypto-js/bcryptjs are load-bearing, per-service migrations documented in docs/conventions/server-frameworks-and-deps.md). 2 remaining @nx/jest executors (bellona build/render-api) recorded as R-14 debt
D-3 four HTTP frameworks Done via policy: fastify (services) + hono (edge/BFF) sanctioned; express/Nest frozen for new code
D-4 549 root scripts Done (verify:phase dispatcher + per-family verify-fleet migration with zero pass/fail flips; 549 → 128 scripts; manifest + scripts/verify.mjs)
D-5 505 Rust workspaces Done (R-18: neith umbrella 599 members + kalika/oya/euterpe umbrellas; refusals documented — yemaya-raster-gpu standalone-by-design, maya proper multi-crate)
D-6 Python no locks Done (root ruff.toml consensus config; uv 57/59 + poetry 21/24 locks committed; 5 never-resolvable manifests documented)
D-7 env monolith Done (per-app .env.example derived from real refs + --check in CI; root stays canonical by design — deviation from R-22's generated-aggregate shape, reason logged)
E DRY collapse Done + enforced: R-10 rollout complete (9 waves, 65 documented refusals); ids via uuid()-wrapper wave + no-handrolled-ids WARN rule; 2026-07-18: conventions ratchet in CI (pino/pg/ioredis/process.env/CircuitBreaker/sleep file-set baselines). http-client/gpu-dispatcher internal-retry rewiring onto @oshun/resilience stays a recorded follow-up (HTTP-typed public API)
F-1 test suffix split Convention + ratchet 2026-07-18: .spec.ts documented as the convention; *.test.ts count frozen at 12,602 in CI. Mass rename declined (config churn, no behavioral gain)
F-2 commit scopes Done (scope-enum reads domains.json; warning-level with a written promotion condition)
F-3 no lib READMEs Done 2026-07-18: 2,466 READMEs generated from package descriptions + registry (owner, docs links, nx commands) via tools/docs/generate-lib-readmes.mjs; hand-written ones untouched
F-4 no name→purpose registry Done (domains.json + generated CODEOWNERS/commitlint; DOMAINS.md carries a canonical-pointer header as of 2026-07-18)
F-5 eslint monolith Deferred with reason: splitting the 1,638-line flat config into per-project configs is high-blast-radius config surgery on 1,646 lint targets; revisit alongside R-14 target standardization
F-6/H-4 god files Done (datasets → JSON with typed shims; six maya monoliths → 46 modules; game-pipeline → 7 modules; export surfaces asserted identical)
F-7 TODO debt Done as specified (burn-down tool + committed ledger) and far beyond: aphrodite scaffold burn-down slices 1–11, socket-auth, health-probe, alerts, notifications, and the analytics warehouse P0 all remediated; remaining plain markers tracked in TODO_BURNDOWN.md
G-1 workflow clones Done (51 v4 gates → gates-manifest + one matrix workflow; 148 → 99 workflows, 102 today with net-new product lines)
G-2 trigger drift Done (the single stale path filter removed from v3-workspace.yml 2026-07-18; both "nightly" workflows carry documented COST(pre-launch) disabled schedules)
G-2b node drift Done (every setup-node pin → node-version-file: .nvmrc; 10 lightweight holdouts documented as deliberate)
G-3 pre-commit builds Done for the finding's core (HTML regen/re-stage removed; hook now gates only)
G-4 inline Isis gates Recorded follow-up under R-14 (move into project targets so affected scopes them); ci.yml remains correctly nx-affected for lint/build/test
G-5 scripts/ codegen mass Corrected + deferred: generate-v2-* fleet is 585K lines of embedded per-artifact data, not shims — collapsing it is a data-extraction refactor with byte-comparison, queued behind owner priorities
G-6 two doc toolchains Done 2026-07-18: scripts/docs/* moved into tools/docs (single home; verifier proven byte-identical, its 111 advisory content-drift findings pre-date the move and are a docs-content follow-up)
H-1 isis↔yemaya edge Done (generic utilities → @oshun/events; isis has zero @yemaya imports; boundary lint clean)
H-3 four BFFs Done (R-13c: @oshun/bff-kit incr 1+2 with fail-closed seams; @oshun/gateway → @oshun/traefik-config; lilith+kalika adopted kit tracing; deeper adoption = owner feature work by design)
H-6 dead/hollow apps Done (urania removed; 2026-07-18 re-verification: all seven formerly-hollow apps now have per-service project.json with zero uncovered tracked sources — v7's shared service_contract.rs is explicitly in the v7Production named input; apps/psyche fully covered; euterpe-studio-web covered)
H-7 layout vocabulary Deferred into R-8/R-16: naming standardization lands with the product-placement decision, not as a standalone rename sweep
R-1 history rewrite (tail) Deferred, owner-gated: git-filter-repo/fresh-clone-point requires coordinating every active worktree and force-pushing main, which is forbidden without the owner driving the window

Deferral grind session (later 2026-07-18)#

Every remaining deferral was either executed or advanced to a measured, owner-executable runbook:

  • Executed: the last 2 @nx/jest stragglers → vitest (D-2); the four inline Isis gates → project targets behind one cached run-many (G-4); vitest-config dedup slice 2 — 303 more files onto presets incl. a rooted factory trio, threshold enforcement proven byte-equivalent (R-14); 392 tsc launcher prefixes normalized across 260 project.json (R-14); the domains source-coverage registry reconciled 111→0 and its gate CI-wired; both large plain blobs LFS-tracked with the seed registry's own pre-existing drift regenerated (A-6 tail); infrastructure/* absorbed into infra/ with offline terraform validate + checker/spec proofs — the R-6 root count is down to the deploy/-gated half; the red isis coverage-formulas gate fixed at the vocabulary level (new studio domain, 15 families authored from workflow definitions, registry canonicalized — 7/7 metrics back at 100%); R-13b pilot — 17 per-format ingest-certification generators collapsed to one manifest-driven generator with normalized byte-equivalence proof; first F-5 composition slice — lilith carve-outs extracted with --print-config byte-identical proof.
  • Adjudicated with evidence (E follow-up): the four shared-internal retry copies are domain-typed public APIs whose observable contracts (additive-above-cap jitter, strategy families, polling semantics, frozen compat surface) the generic @oshun/resilience cannot express without silent behavior change — refusals recorded at each site, legacy copy @deprecated, ratchet blocks new duplication.
  • Runbooks (owner-gated on hard evidence): services/→apps/ (79-file live-reference inventory; deploy-hetzner.yml auto-fires on main pushes and is under active parallel development) — SERVICES_TO_APPS_MIGRATION_ RUNBOOK_2026-07-18.md; history rewrite measured on a real filter-repo dry run (pack 1.2 GiB → 889 MiB) — HISTORY_REWRITE_RUNBOOK_2026-07-18.md; R-8 decided (split convention binding; staged V5→V2→V4 convergence) — R8_PRODUCT_PLACEMENT_DECISION_2026-07-18.md.

Prelaunch-authorized execution (later still, 2026-07-18)#

The owner confirmed the platform is prelaunch on everything, dissolving the deploy-risk gating. Executed: services/ → apps/ landed (B-5/R-9 closed: concordia, psyche flattened beside admin/, metis python backend as apps/metis/service; all 79 live references rewired; concordia 122/122; python compileall green — repairing a mojibake-corrupted dict that had made psyche knowledge-base cleaning.py unparseable since authoring; nx graph, domains verifier, env sync, filter glob-tests all green; the stub scan gained R100 rename-awareness so pure moves stop re-litigating pre-existing hits). R-13b wave 2: packaging + integrity families (33 scripts) joined the manifest-driven generator with 66/66 byte-equivalence; the contract family is a documented refusal (configs carry per-format code). Remaining in the fleet: contract ×14, engine-bundle ×4, self-contained bulk. Still queued: R-6 deploy/* half, R-8 staged V5/V2/V4 convergence (both now prelaunch-unblocked, each a dedicated change); history rewrite remains owner-executed (force-push policy).

Net additions in this reconciliation pass (2026-07-18): ADR-0073 + changesets removal (C-8); conventions ratchet + CI wiring + baselines (E, R-11, F-1); 2,466 generated lib READMEs + generator (F-3); docs tooling single home (G-6); DOMAINS.md canonical pointer (F-4); sdks/README (R-9); orphan libs/tsconfig.test.json + stale v3-workspace path filter removed (B-6, G-2); VRM4U submodule ignore = dirty (R-1 status noise); stray in-place compile artifacts cleaned from the working tree. Deferred items are all owner-gated (deploy windows, history rewrite, product-tree moves) or explicitly cost-adjudicated (eslint split, tsconfig presets, run-commands standardization) — each carries its reason above and in the execution logs.