# Module Consolidation Audit Document **Date:** 2026-02-25 **Prepared by:** AI-assisted planning (Claude Opus 4.6) **Update note (2026-02-25):** Domain-first sprint rework and DB-merge planning updates were produced by Codex. See docs/implplan/AUDIT_20260225_cli_ui_module_reference_matrix.md and updated sprints 203, 204, 205, 206, 208, 211, 216, 218. **Review note (2026-02-25):** Post-review corrections applied by Claude Opus 4.6: fixed CryptoPro path, added Zastava to exclusion list, corrected module counts, added SbomService consolidation (Sprint 220), added compiled-model invalidation risk, rewrote execution order with coordination constraints, added standalone module rationale section. **DB merge verdict (2026-02-25):** Deep analysis of all 7 proposed DB merges completed. All services share one PostgreSQL database (`stellaops_platform`) with schema-level isolation. Verdicts: REJECT 4 merges (Advisory/203, Trust/204, Orchestration/208, Identity/216) as source-consolidation only; PROCEED 2 DbContext merges (VEX/205, Offline/211); PROCEED 1 empty placeholder deletion (Policy/206). Sprint files amended accordingly. See Section 9 for details. **Scope:** 22 sprint files (SPRINT_20260225_200 through SPRINT_20260225_221, including companion Sprint 219 for EF compiled models and Sprint 221 for Orchestrator rename) **Sprint files location:** `docs/implplan/SPRINT_20260225_2*.md` --- ## 1. Original Request The owner reviewed the Stella Ops monorepo and identified that the repository had grown to **~60 module directories** under `src/` (plus infrastructure directories like `__Libraries/`, `__Tests/`, `__Analyzers/`). The request, in the owner's words: > "you have to think from stella ops architecture position. we have now 40+ modules. this is bit too much. ideally the number should be = purpose/schema + workers" The guiding principle: **one module = one distinct purpose or schema domain + its workers**. Modules that share a schema, serve the same domain, or exist as thin deployment hosts for another module's libraries should be consolidated into their parent domain. The owner explicitly excluded crypto modules from consolidation: > "i agree for all consolidation but the crypto one related. these modules are simulator smremote and cryptopro. so these needs to be kept as is." The owner also requested: > "create sprints for the consolidation. one per domain. make sure to include cli, ui, documentation, tests and other related work after the core consolidation work. the sprints needs to be very detailed." --- ## 2. Analysis Method The consolidation candidates were identified through: 1. **Dependency graph analysis** — mapping every `ProjectReference` across all `.csproj` files in the repo to find which modules are consumed by which, and identifying single-consumer or zero-consumer modules. 2. **Domain alignment** — evaluating whether two modules operate on the same schema, data domain, or workflow stage (e.g., Signer produces DSSE envelopes that Attestor logs — same trust domain). 3. **Deployment boundary audit** — confirming that consolidation is **organizational only** (moving source code directories), NOT a service merge. Each absorbed module's WebService/Worker keeps its own Docker container and port. 4. **Consumer count** — modules with zero external consumers are prime candidates. Modules with 1-2 consumers that are within the same domain are also candidates. 5. **Orphan library scan** — searching every `.csproj` and `.cs` file for `ProjectReference` and `using` statements to confirm libraries with zero production consumers. --- ## 3. Consolidation Decisions — Sprint by Sprint ### Sprint 200 — Delete `src/Gateway/` **Action:** Delete (not absorb) **Rationale:** Gateway is dead code. The canonical `StellaOps.Gateway.WebService` already lives inside `src/Router/StellaOps.Gateway.WebService/` with source comments confirming "now in same module." The `src/Gateway/` directory is a leftover from a previous migration. Zero consumers reference it. The Router version is confirmed as a superset. --- ### Sprint 201 — Scanner absorbs Cartographer **Action:** Move `src/Cartographer/` (1 csproj) → `src/Scanner/` **Rationale:** Cartographer materializes SBOM graphs for indexing. SBOM processing is Scanner's domain. Cartographer has **zero external consumers** — it depends on Policy and Auth but nothing depends on it outside itself. Its AGENTS.md already points to the Graph module for required reading. Single-purpose library that belongs under its only consumer's domain. --- ### Sprint 202 — BinaryIndex absorbs Symbols **Action:** Move `src/Symbols/` (6 csproj) → `src/BinaryIndex/` **Rationale:** Symbols provides debug symbol storage and resolution. Its primary consumer is `BinaryIndex.DeltaSig`. The only other consumer is `Cli.Plugins.Symbols` (a thin CLI plugin loader). Same data domain — binary artifact analysis. Symbols.Server keeps its own container. The existing Symbols architecture doc was stale (described a monolithic layout while actual code has 5 projects), which further indicates this was an under-maintained satellite module. --- ### Sprint 203 — Concelier absorbs Feedser + Excititor **Action:** Move `src/Feedser/` (2 csproj) + `src/Excititor/` (17 csproj) + `StellaOps.DistroIntel` → `src/Concelier/` **Rationale:** - **Feedser** is a backport evidence library. Its architecture doc explicitly states "Primary consumer: Concelier ProofService." Also consumed by Attestor.ProofChain and Scanner.PatchVerification, but the domain home is Concelier (advisory feed processing). - **Excititor** is the VEX feed collection service with connectors for Cisco, MSRC, Oracle, RedHat, SUSE, Ubuntu, OpenVEX, etc. Advisory ingestion is the same domain as Concelier (advisory feed curation). Excititor feeds VexHub which feeds VexLens — all VEX/advisory pipeline. - **DistroIntel** is a single-consumer library — only `Concelier.BackportProof` references it. - All three share the advisory/feed data domain. Excititor keeps its own WebService + Worker containers. --- ### Sprint 204 — Attestor absorbs Signer + Provenance **Action:** Move `src/Signer/` (5 csproj) + `src/Provenance/` (2 csproj) → `src/Attestor/` **Rationale:** Same trust domain — keys, DSSE signing, transparency logs. Signer produces DSSE envelopes, Attestor logs them as attestations. Provenance is a thin attestation library + CLI forensic tool. The three together form the complete evidence trust chain: sign → attest → verify provenance. Signer's WebService keeps its own container. Provenance CLI tool may optionally move to Tools. --- ### Sprint 205 — VexLens absorbs VexHub **Action:** Move `src/VexHub/` (3 csproj) → `src/VexLens/` **Rationale:** Same VEX data domain. VexHub aggregates and validates VEX statements; VexLens adjudicates consensus over them. They operate on the same data (VEX documents) and the same workflow stage (VEX adjudication). VexHub keeps its own WebService container. --- ### Sprint 206 — Policy absorbs Unknowns **Action:** Move `src/Unknowns/` (5 csproj) → `src/Policy/` **Rationale:** Unknowns.Core already **depends on Policy** — it imports Policy types. Unknown component tracking is a policy governance concern (what is the policy for components whose provenance is unknown?). External consumers (Platform.Database, Scanner.Worker, Scanner.MaterialChanges) reference Unknowns.Core, but the domain home is Policy. Unknowns.WebService keeps its own container and EF Core migrations. --- ### Sprint 207 — Findings absorbs RiskEngine + VulnExplorer **Action:** Move `src/RiskEngine/` (1 csproj) + `src/VulnExplorer/` (1 csproj) → `src/Findings/` **Rationale:** Both are single-csproj modules operating on the same data domain — vulnerability findings. RiskEngine computes risk scores over findings. VulnExplorer is the API surface for browsing findings. Both are thin enough (1 project each) that maintaining separate top-level directories is overhead. Low risk due to small scope. --- ### Sprint 208 — Orchestrator absorbs Scheduler + TaskRunner + PacksRegistry **Action:** Move `src/Scheduler/` (8 csproj) + `src/TaskRunner/` + `src/PacksRegistry/` → `src/Orchestrator/` **Rationale:** All three are "schedule and execute work" — same workflow lifecycle domain. Orchestrator owns the job lifecycle, Scheduler adds trigger/cron logic, TaskRunner adds DAG execution, PacksRegistry stores task pack definitions. They form a complete orchestration pipeline. All keep their deployable containers. --- ### Sprint 209 — Notify absorbs Notifier **Action:** Move `src/Notifier/` (2 csproj) → `src/Notify/` **Rationale:** Notifier is a **thin deployment host** for Notify libraries. The Notifier WebService and Worker only reference Notify libraries — they contain no unique logic. This was a 2025-11-02 separation decision that the architecture notes suggest should be revisited. The deployment hosts stay as separate containers, but the source code belongs with the libraries they host. --- ### Sprint 210 — Timeline absorbs TimelineIndexer **Action:** Move `src/TimelineIndexer/` (4 csproj) → `src/Timeline/` **Rationale:** CQRS split (read/write) is an **internal architecture pattern**, not a module boundary. Timeline and TimelineIndexer operate on the same schema domain (timeline events). TimelineIndexer is the write side (event ingestion and indexing); Timeline is the read side. ExportCenter references TimelineIndexer.Core — this cross-module reference path will be updated. TimelineIndexer Worker keeps its own container. --- ### Sprint 211 — ExportCenter absorbs Mirror + AirGap **Action:** Move `src/Mirror/` (1 csproj) + `src/AirGap/` → `src/ExportCenter/` **Rationale:** - **Mirror** creates offline mirror bundles — ExportCenter's domain. Mirror's shell scripts already reference ExportCenter. Zero external consumers. Single csproj. - **AirGap** handles offline bundle creation, sync, and policy. Natural fit with ExportCenter — both deal with offline/air-gap distribution. AirGap components keep their project names for offline kit identity. --- ### Sprint 212 — Tools absorbs Bench + Verifier + Sdk + DevPortal **Action:** Move `src/Bench/` (5 csproj) + `src/Verifier/` (1 csproj) + `src/Sdk/` (2 csproj) + `src/DevPortal/` → `src/Tools/` **Rationale:** All four are **non-service, developer-facing tooling** with no production deployment. Bench runs benchmarks, Verifier is a CLI bundle verifier, Sdk contains a code generator + release tool, DevPortal is the developer portal. None have Docker services. None are consumed by production modules. Tools already has 7+ csproj — these are natural additions. Low risk. --- ### Sprint 213 — AdvisoryAI absorbs OpsMemory **Action:** Move `src/OpsMemory/` (2 csproj) → `src/AdvisoryAI/` **Rationale:** OpsMemory is the AI's operational memory / RAG vector store. It is **only consumed by AdvisoryAI**. AdvisoryAI currently references OpsMemory via ProjectReference. Same domain — AI knowledge management. OpsMemory WebService keeps its own container. --- ### Sprint 214 — Integrations absorbs Extensions **Action:** Move `src/Extensions/` (VS Code + JetBrains plugins) → `src/Integrations/__Extensions/` **Rationale:** Extensions are developer-facing IDE plugins that consume the same Orchestrator/Router APIs as other integrations. They are logically part of the Integrations domain (toolchain integrations). Note: these are **non-.NET** (TypeScript/Kotlin) — no .csproj files. Zero external consumers. No Docker service. Placed under `__Extensions/` (not `__Plugins/`) to avoid confusion with the Integrations plugin framework. --- ### Sprint 215 — Signals absorbs RuntimeInstrumentation **Action:** Move `src/RuntimeInstrumentation/` → `src/Signals/` **Rationale:** RuntimeInstrumentation provides eBPF/Tetragon event adapters that feed into Signals. Same domain — runtime observability. Critical finding: RuntimeInstrumentation has **no .csproj files** — source code exists (12 .cs files) but lacks build integration. Zero external consumers (impossible to reference without .csproj). Signals already has `StellaOps.Signals.Ebpf` which may overlap. The sprint includes an audit task to determine integration strategy. --- ### Sprint 216 — Authority absorbs IssuerDirectory **Action:** Move `src/IssuerDirectory/` (6 csproj + client lib) → `src/Authority/` **Rationale:** IssuerDirectory manages issuer metadata, keys, and trust — a natural subdomain of Authority (identity and trust). IssuerDirectory **depends on Authority** for authentication. Only 2 external consumers (Excititor, DeltaVerdict) via a client library. IssuerDirectory has its own PostgreSQL schema (`issuer_directory`) which remains unchanged. IssuerDirectory WebService keeps its own container. --- ### Sprint 217 — Orphan Library Cleanup **Action:** Archive `StellaOps.AdvisoryLens` + `StellaOps.Resolver` to `src/__Libraries/_archived/` **Rationale:** - **AdvisoryLens** — zero production consumers. Not in main solution file. Has tests but nothing imports it. Appears to be intended for a feature not yet implemented. - **Resolver** — zero production consumers. In main solution file but nothing imports it. Research/PoC code for deterministic verdict resolution with extensive SOLID review documentation. - **SettingsStore** was initially suspected but **confirmed active** — used by ReleaseOrchestrator, Platform, Cli, and AdvisoryAI. Removed from cleanup scope. - Archive (not delete) preserves code history and enables reactivation. --- ### Sprint 218 — Final Documentation Consolidation **Action:** Update all docs to mirror new `src/` structure **Rationale:** This is the cleanup sweep that runs LAST, after all source moves (200-220) are complete. It updates `CLAUDE.md`, `docs/INDEX.md`, `docs/07_HIGH_LEVEL_ARCHITECTURE.md`, validates all cross-references, and ensures zero broken links to absorbed module docs. Depends on all other sprints being DONE. --- ### Sprint 219 — EF Compiled Model & Migration Consistency (companion sprint, DONE) **Action:** Generate EF Core compiled models for 5 remaining real DbContexts; convert code-first migrations to raw SQL **Rationale:** Foundation sprint completed before consolidation execution. Ensures all real DbContexts have compiled models, factory infrastructure, and guard tests. Covers ExportCenter, Triage, ProofService, Integration, and Provcache contexts. Three stub contexts (SbomService, PacksRegistry, TaskRunner) were deferred — SbomServiceDbContext stub has since been deleted, and PacksRegistry/TaskRunner will be addressed during Sprint 208 orchestration domain merge. **Status:** All 6 tasks DONE as of 2026-02-25. **Note:** Source moves in domain sprints (203, 206, 208, etc.) will require updating `` paths for compiled model assembly attributes in moved `.csproj` files. This is a non-breaking path fixup (builds produce a duplicate attribute warning, not a failure) but should be included in each sprint's source-move verification step. --- ### Sprint 220 — Scanner absorbs SbomService **Action:** Move `src/SbomService/` â†' `src/Scanner/` **Rationale:** SbomService generates and processes SBOMs from scanned artifacts — this is squarely within Scanner's domain (scan â†' produce SBOM â†' index). The SbomServiceDbContext stub was already deleted in a prior session, removing the persistence complication. SbomService has its own WebService which keeps its own container. Low consumer count — primarily consumed by Scanner and Orchestrator pipelines. Moving it under Scanner follows the same “one module = one domain” principle applied throughout this consolidation. --- ### Sprint 221 â€" Rename Orchestrator domain **Action:** Rename `src/Orchestrator/` â†' `src//` (name TBD in TASK-221-001) **Rationale:** `Orchestrator` creates persistent confusion with `ReleaseOrchestrator` (the core product feature â€" release promotion pipeline). After Sprint 208 consolidates Scheduler/TaskRunner/PacksRegistry under Orchestrator, the rename gives the domain an unambiguous identity. Scope: 3,268 namespace references, 336 C# files, 36 external ProjectReferences, Docker images, Helm, API routes, authority scopes, 40+ TypeScript files. PostgreSQL schema name `orchestrator` is preserved for data continuity. Pre-alpha with zero clients makes this the last low-cost window. --- ## 4. What Does NOT Change - **Deployment boundaries** — every absorbed module's WebService/Worker keeps its own Docker container, port, and image name. This is organizational consolidation, not service merge. - **Project names** — cross-module libraries keep their original names to avoid breaking downstream references. Only Cartographer and Symbols get renamed (they have zero or contained consumers). - **Database schemas** — all schemas and migrations are preserved. No schema renames. - **Crypto modules** — `src/SmRemote/`, `src/Zastava/`, and `src/Cryptography/` (which contains CryptoPro as a plugin at `src/__Libraries/StellaOps.Cryptography.Plugin.CryptoPro/`) are untouched per owner's explicit instruction. Note: there is no top-level `src/CryptoPro/` directory — CryptoPro is a plugin within the Cryptography module. - **Core standalone modules** — Platform, Router, Web, Cli, Doctor, Telemetry, EvidenceLocker, Graph, ReachGraph, Plugin, Registry, ReleaseOrchestrator, Remediation, and Replay remain as independent top-level directories. See Section 8 for rationale on each. --- ## 5. Expected Outcome | Metric | Before | After | |--------|--------|-------| | Top-level `src/` module directories | ~60 | ~33 | | Infrastructure directories (`__Libraries/`, `__Tests/`, `__Analyzers/`) | 3 | 3 (unchanged) | | Modules with 0 external consumers | 9 | 0 (absorbed or archived) | | Single-consumer satellite modules | 7 | 0 (absorbed into parent) | | Thin deployment hosts as separate modules | 3 | 0 (moved to library host) | | Orphan libraries | 3 | 0 (1 confirmed active, 2 archived) | | Modules absorbed or deleted | â€" | 27 | | Crypto modules (untouched) | 3 | 3 (SmRemote, Zastava, Cryptography) | --- ## 6. Risk Summary | Risk | Mitigation | |------|-----------| | Namespace renames may break serialized type names | Grep for `typeof()`, `nameof()`, JSON `$type` discriminators before renaming | | Cross-module `ProjectReference` paths break during move | Update all consumer `.csproj` paths atomically; verify with `dotnet build StellaOps.sln` | | EF Core compiled models / migration identity | Preserve migration file names and schema names unchanged | | **Compiled model path invalidation after source moves** | Sprint 219 (DONE) generated compiled models whose `.csproj` files contain `` for assembly attributes. Domain sprints that move these projects (203, 206, 208) must update these paths as part of the source-move verification. Builds emit a duplicate attribute warning (not failure) if missed, but should be fixed proactively. | | RuntimeInstrumentation has no .csproj | Sprint includes audit task to create build integration or merge into existing Signals.Ebpf | | Excititor has 17 csproj (largest move) | Move in batches: core+persistence first, then connectors, then deployables | | Authority grows to 35 csproj after absorbing IssuerDirectory | Justified — all are identity/trust domain. Authority already well-structured with `__Libraries/` and `__Tests/` conventions | | **Parallel sprint coordination risk** | Sprints 203/204 and 203/205 touch overlapping cross-module references (Feedser/Provenance, Excititor/VexHub). Must be serialized or carefully coordinated — see Section 7 execution tiers. | --- ## 7. Sprint Execution Order ### Completed - **Sprint 219** (EF Compiled Models) — DONE. Foundation work completed before consolidation. ### Tier 1 — Independent, no cross-sprint conflicts (safe to run in parallel) These sprints touch isolated modules with no overlapping cross-references: - **Sprint 200** — Gateway deletion (dead code, zero risk) - **Sprint 201** — Scanner absorbs Cartographer - **Sprint 202** — BinaryIndex absorbs Symbols - **Sprint 207** — Findings absorbs RiskEngine + VulnExplorer - **Sprint 209** — Notify absorbs Notifier - **Sprint 210** — Timeline absorbs TimelineIndexer - **Sprint 212** — Tools absorbs Bench + Verifier + Sdk + DevPortal - **Sprint 213** — AdvisoryAI absorbs OpsMemory - **Sprint 214** — Integrations absorbs Extensions - **Sprint 215** — Signals absorbs RuntimeInstrumentation - **Sprint 217** — Orphan Library Cleanup - **Sprint 220** — Scanner absorbs SbomService (can run in parallel with 201 if source moves don't overlap; serialize if both touch Scanner solution file simultaneously) ### Tier 2 — Coordination required (serialize within group) These sprints have overlapping cross-module references and must be executed in the order shown: **Group A — Advisory/VEX pipeline** (serialize): 1. **Sprint 203** — Concelier absorbs Feedser + Excititor (moves Excititor, which feeds VexHub) 2. **Sprint 205** — VexLens absorbs VexHub (depends on Excititor's new path from Sprint 203) **Group B — Advisory/Trust cross-references** (serialize): 1. **Sprint 203** — Concelier absorbs Feedser + Excititor (moves Feedser, referenced by Attestor) 2. **Sprint 204** — Attestor absorbs Signer + Provenance (updates Feedser references to new paths) **Group C — Orchestration domain** (serialize within): 1. **Sprint 208** — Orchestrator absorbs Scheduler + TaskRunner + PacksRegistry **Group D — Identity cross-references** (coordinate with Group A): 1. **Sprint 216** — Authority absorbs IssuerDirectory (IssuerDirectory client used by Excititor — coordinate with Sprint 203 if running close together) **Group E — Offline domain** (independent of other groups): 1. **Sprint 211** — ExportCenter absorbs Mirror + AirGap **Group F — Policy domain** (independent of other groups): 1. **Sprint 206** — Policy absorbs Unknowns **Practical serialization**: Run Sprint 203 first among Tier 2 groups since it is the largest move (17 csproj) and unblocks both Group A and Group B. After 203 completes, Sprints 204, 205, and 216 can proceed. Sprints 206, 208, and 211 can run any time. ### Tier 2.5 — Post-consolidation rename (depends on Sprint 208 being DONE) - **Sprint 221** — Rename Orchestrator domain to resolve ReleaseOrchestrator naming collision (3,268 namespace references, 336 C# files, Docker/Helm/API routes/authority scopes). PostgreSQL schema name preserved for data continuity. ### Tier 3 — Final sweep (depends on all Tier 1 + Tier 2 + Tier 2.5 being DONE) - **Sprint 218** — Final Documentation Consolidation --- ## 8. Standalone Module Rationale The following modules remain as independent top-level directories after consolidation. This section documents why each was not absorbed into another domain, to preempt future “why didn't we consolidate X?” questions. | Module | Why standalone | |--------|---------------| | **Platform** | Cross-cutting infrastructure host (health checks, config distribution, service discovery). Not domain-specific — consumed by all modules. | | **Router** | API gateway / reverse proxy. Already absorbed Gateway (Sprint 200). Sits at the network edge, not inside any domain. | | **Web** | Angular SPA. Single UI project, not a backend domain. | | **Cli** | CLI tool. Cross-cutting client, not a backend domain. | | **Doctor** | Diagnostics and health monitoring. Cross-cutting operational concern, not tied to a single domain. | | **Telemetry** | Shared observability library (metrics, tracing, logging). Consumed by nearly every module — shared infrastructure, not a domain. | | **EvidenceLocker** | Evidence storage. Could be argued as part of the trust domain (Attestor), but it is a storage service consumed by multiple domains (Policy, Orchestrator, Attestor, Scanner) for different evidence types. Multi-consumer shared service. | | **Graph** | Graph data structures and algorithms library. Shared infrastructure consumed by ReachGraph, Scanner/Cartographer, and others. Not a domain-specific service. | | **ReachGraph** | Reachability analysis service. Uses Graph but serves a specific security analysis purpose (dependency reachability for vulnerability assessment). Distinct enough from Scanner (which uses reachability results but doesn't compute them). | | **Plugin** | Plugin framework and hosting infrastructure. Cross-cutting extension mechanism, not domain-specific. | | **Registry** | Container/artifact registry service. Manages artifact storage and distribution — its own distinct concern separate from scanning (Scanner analyzes) or orchestration (Orchestrator schedules). | | **ReleaseOrchestrator** | Release promotion workflow engine. The core “promote through environments” logic. Could be argued as part of Orchestrator, but ReleaseOrchestrator is the business-critical release pipeline while Orchestrator is the generic job/schedule engine. Different concerns despite similar names. | | **Remediation** | Remediation workflow engine. Produces actionable fix plans from findings. Could be argued as part of Findings, but remediation is an active response domain (suggest fixes, track remediation progress) while Findings is a passive data domain (store and query vulnerability data). | | **Replay** | Deterministic evidence replay for verification. Could be argued as part of the trust domain (Attestor), but Replay serves an independent verification purpose (re-derive any past decision from evidence). Used by compliance auditors, not just trust infrastructure. | | **SmRemote** | HSM/crypto remote signing bridge. Excluded from consolidation per owner instruction (crypto module). | | **Zastava** | Crypto signing service (HSM bridge, regional crypto). Excluded from consolidation per owner instruction (crypto module). | | **Cryptography** | Crypto plugin framework (contains CryptoPro, GOST, SM plugins). Excluded from consolidation per owner instruction (crypto module). | --- ## 9. DB Merge Verdicts (2026-02-25) ### Context All Stella Ops services share a single PostgreSQL database (`stellaops_platform` at `db.stella-ops.local:5432`). Domain isolation is achieved through PostgreSQL schemas, not separate databases. The original consolidation sprints proposed "DB merges" for 7 domain consolidations. After deep analysis, the proposed merges are really about merging EF Core DbContexts (code-only) or merging PostgreSQL schemas (data migration). Since all data is already in one database, schema merges provide marginal operational benefit at significant code risk. ### Verdict summary | Sprint | Domain | Verdict | Rationale | Task impact | |--------|--------|---------|-----------|-------------| | 203 | Advisory (Concelier) | **REJECT** | 49 entities across 5 schemas (`vuln`, `feedser`, `vex`, `proofchain`, `advisory_raw`). Distinct lifecycles. Coupling risk too high. | 8 tasks reduced to 4 (source move only) | | 204 | Trust (Attestor) | **REJECT** | Security boundary between signer key material and attestation evidence is a deliberate feature. Merging widens credential compromise blast radius. | 8 tasks reduced to 4 (source move only) | | 205 | VEX (VexLens) | **PROCEED** (DbContext merge) | 9 entities, zero name collisions. Low-risk DbContext consolidation. Schemas stay separate. | 5 tasks reduced to 4 (no dual-write/backfill) | | 206 | Policy | **PROCEED** (delete placeholder) | UnknownsDbContext has 0 entities, 0 tables. Just delete the empty class. | 6 tasks reduced to 4 (no data migration) | | 208 | Orchestration | **REJECT** | 39 + 11 entities with Jobs/JobHistory name collisions. Fundamentally different job models (pipeline runs vs. cron). | 8 tasks reduced to 3 (source move only) | | 211 | Offline (ExportCenter) | **PROCEED** (DbContext merge) | 7 entities, zero name collisions. Low-risk DbContext consolidation. Schemas stay separate. | 5 tasks reduced to 4 (no dual-write/backfill) | | 216 | Identity (Authority) | **REJECT** | Most security-critical domain. Merging IssuerDirectory into AuthorityDbContext would give any issuer-metadata code path access to authentication internals. | 6 tasks reduced to 4 (source move only) | ### Impact The verdicts eliminated ~42 data migration task phases (expand, dual-write, backfill, cutover, rollback) across 7 sprints, replacing them with either: - **Source move only** (4 rejected domains): no schema changes, no data migration, no runtime risk. - **DbContext-level merge** (2 proceeding domains): code-only change, compiled model regeneration, targeted integration tests. - **Empty placeholder deletion** (1 domain): trivial cleanup with zero data risk. ### Architectural rule established The analysis prompted the addition of Section 16 (Domain Ownership and Boundary Rules) to `docs/code-of-conduct/CODE_OF_CONDUCT.md`, codifying: - Single database / schema isolation as an architectural invariant - DbContext ownership rules per domain - Cross-domain dependency rules (no direct persistence references) - Schema migration ownership rules