Slice 5 of #514 (modular monolith). Track B — enforcement only, no production code. Needs #842.
Nothing that crosses a module seam may expose persistence.
Scope
Reflection over every public interface in Cluckwork.Application.Features.* and
Cluckwork.Application.Common, recursing through parameter and return types. Reject any signature
reaching DbContext, DbSet, IQueryable, an EF metadata type, an aggregate base, or a repository
implementation type.
Why now rather than with the contracts
The guard is currently close to vacuous — there are zero IQueryable returns in Application
today, so it has no exemptions and starts perfectly clean. That is exactly when a pin is cheap. Add
it after the first contract ships and it arrives with a backlog of things to argue about.
Its real job is the day someone adds Task<IQueryable<Expense>> Query() to a repository because it
made one call site shorter.
Done when
| Mutation |
Expected |
add IQueryable<Flock> Query() to IFlockRepository |
red |
return a DbSet<Expense> from any public Application interface |
red |
accept an AppDbContext parameter on one |
red |
| return a plain DTO or a domain value object |
green — these are the allowed shapes |
Explicitly not in this slice
Does not constrain Cluckwork.Infrastructure internals, where EF types are the point. Does not
define any module contract — it only fixes what a contract will be allowed to say once one exists.
Slice 5 of #514 (modular monolith). Track B — enforcement only, no production code. Needs #842.
Nothing that crosses a module seam may expose persistence.
Scope
Reflection over every public interface in
Cluckwork.Application.Features.*andCluckwork.Application.Common, recursing through parameter and return types. Reject any signaturereaching
DbContext,DbSet,IQueryable, an EF metadata type, an aggregate base, or a repositoryimplementation type.
Why now rather than with the contracts
The guard is currently close to vacuous — there are zero
IQueryablereturns in Applicationtoday, so it has no exemptions and starts perfectly clean. That is exactly when a pin is cheap. Add
it after the first contract ships and it arrives with a backlog of things to argue about.
Its real job is the day someone adds
Task<IQueryable<Expense>> Query()to a repository because itmade one call site shorter.
Done when
IQueryable<Flock> Query()toIFlockRepositoryDbSet<Expense>from any public Application interfaceAppDbContextparameter on oneExplicitly not in this slice
Does not constrain
Cluckwork.Infrastructureinternals, where EF types are the point. Does notdefine any module contract — it only fixes what a contract will be allowed to say once one exists.