Skip to content

[C] #514 slice 17: assembly split — conditional on Track A/B evidence #859

Description

@mforce

Amended 2026-10-04: scope changed by the owner. Step 1 replaces module-ledger.json, tenant-bypass-allowlist.json and filter-free-set-sites.tsv with typed C# registries, with no assembly split. The entry-condition evidence and the options comparison are in this comment. The original body is kept below for history.

Important

Track C is unscheduled. These slices move production code, and the 2026-08 design's own status
line still governs: "proposed architecture; no production refactor is authorized by this
document."
Filed so the analysis is tracked work rather than a comment, not as a commitment to
run it.

The 2026-09-14 re-plan
recommends gating Track C on evidence from Tracks A and B: if the #842 ratchet fires repeatedly in
real pull requests, these become worth their cost; if it stays quiet, they do not. Track C is
57–95 focused engineering days and produces no user-visible change.

Read the re-plan before picking any of these up. Several assumptions in the 2026-08 plan are
corrected there.

Split the modules into separate assemblies so the compiler enforces what the ledger has been
watching. Conditional — see the bar below.

This slice has an entry condition, and it is not "the others finished"

Run it only if Tracks A and B produced evidence that a boundary was actually crossed by accident.
If the ratchet (#842) and the adapter guard (#846) sat quiet through the whole of Track C, then a
source walk was sufficient, nobody was reaching where they should not, and this buys a compiler error
for a problem that did not occur.

That is not a formality. This is the single most expensive slice in the epic and the one most likely
not to earn its cost.

What it buys that nothing before it does

Peer implementations become genuinely invisible — not "we notice", but "it does not compile".
Everything in Tracks A and B is detection. This is prevention.

What it costs, priced honestly

Per new project: a packages.lock.json under Central Package Management (#684), a COPY line in the
Dockerfile restore layer, and for a test project a CI matrix leg (#775), a
SolutionTestProjectSplitTests reconcile and a tools/coverage/collect.sh entry. Multiply by the
number of assemblies.

Plus a namespace rename across the tenancy registry's symbol-keyed rows and the filter-free-set TSV —
which is precisely the re-pinning churn #632 keyed those by symbol to avoid. Do it once, deliberately,
in a single reviewable commit, or not at all.

The cross-owner foreign-key mechanism, already solved

A cross-owner FK is never expressed through EF's generic fluent API — that type parameter is what
forces a Platform.Persistence ↔ Module.Implementation cycle. Use the fully string-based
non-generic form from the owner's own configuration, e.g.

builder.HasOne("Cluckwork.Domain.Flocks.Flock").WithMany().HasForeignKey("FlockId")
       .HasConstraintName("FK_Expenses_Flocks_FlockId").OnDelete(DeleteBehavior.Restrict);

The fully-qualified name and the Restrict delete behaviour are both load-bearing — a typo'd
namespace or a dropped OnDelete each independently fail the model-equivalence check. This
reproduces exactly what InitialCreate already created, so it needs no new migration; emitting
AddForeignKey for an existing constraint name fails on every already-migrated database.

Done when

The six architecture mutations from the 2026-08 design §8 go red at assembly level rather than at
source level. EF model digest identical. Full solution, frontend and simulation verification green.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:apiAPI/endpoint layerepic-514Modular monolith architecture (#514)priority:tier4Deferred or speculativesize:LSeveral days; wide blast radius or unresolved scopesliceThin vertical work itemtrack:C#514 Track C — moves production code; UNSCHEDULED, needs authorisation

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions