Skip to content

refactor(arch): move Farm into Modules/Farm - #1096

Merged
mforce merged 6 commits into
mainfrom
refactor/1087-farm-module
Oct 6, 2026
Merged

mforce merged 6 commits into
mainfrom
refactor/1087-farm-module

Conversation

@mforce

@mforce mforce commented Oct 5, 2026 •

Copy link
Copy Markdown
Owner

Refs #1087

S7 of the package-by-module design: Farm moves into Modules/Farm in Domain, Application and Api. This is a pure move with no behaviour change. Its repositories and EF configuration stay in place until S9. UserRoleAssignment stays in Farm (Domain/Modules/Farm/Accounts), keeping its UserRoleAssignments table-owner override (Access) and its seam entry. Rebased onto ccb55584 (#1095, Access). I reset onto main and re-ran the codemod commit by commit (split, then move and prune, then marks). The hand-written comment and reason fixes cherry-picked unchanged. The re-key did not cherry-pick, because Access had re-keyed the neighbouring Symbol lines, so it was re-applied to the rebased rows: the same 6 hash changes, with the guard reporting the same new hashes under Access's new Symbols. Proofs compare head 31b4b347 with base ccb55584.

Review order

  1. split (mechanical): FarmLogoMetadata, FarmLogoContent and FarmBrandingHashes leave IFarmLogoRepository.cs. Each is a verbatim slice.
  2. move (generated; skim it): 36 git mvs. Namespaces come from the folders, and the tool rewrote references, usings, ledger strings (including Farm's Seam: IAccountRepository, Account, UserRoleAssignment), snapshot entity names and paths. The rules file Namespaces now holds Cluckwork.Domain.Modules.Farm and Cluckwork.Application.Modules.Farm; Implementations is unchanged (S9). No codemod fix was needed.
  3. fix (read these):
    • IFarmModule's comment now names the Contracts folder (it was the last "types marked [ModuleContract]" comment).
    • The SPA slug-pattern comment and the UserRoleAssignments override reason now name Modules/Farm/Accounts. The override row itself is unchanged.
  4. re-key (read this one): the 6 filter-free identities in IdentityProvider, separately and with a namespace-only proof (below).
  5. marks: the 10 Farm [ModuleContract] marks deleted.

Re-key proof (#632)

RequireActiveOwnerAsync, CountOtherActiveOwnersAsync and DisableUserAsync spell Cluckwork.Domain.Accounts.Roles.Owner in full inside their queries, so their token hashes follow the namespace. The names stay fully qualified (not shortened to a using), and the hasher is unchanged.

Member Sets Base → head (real GuardScanner.QuerySignatureOf on Modules/Access/Identity/IdentityProvider.cs at ccb55584 and at the head) Whole-member token streams
RequireActiveOwnerAsync db.Roles, db.UserRoles aed7b297 → 71384910 166 → 170 tokens; equal after normalizing only Cluckwork.Domain.Accounts. → Cluckwork.Domain.Modules.Farm.Accounts.
CountOtherActiveOwnersAsync db.Roles, db.UserRoles 57009ecd → b7bada95 95 → 99; equal after the same normalization
DisableUserAsync db.Roles, db.UserRoles 9b6fec98 → 9e5764d7 415 → 419; equal after the same normalization

Each member gains exactly four tokens (Modules . Farm .). No predicate changed. These are the three old→new pairs the design predicted and Astra measured. The 40 allow-list hashes are unchanged.

Checks at push time (rebased head 31b4b347)

Check Result
dotnet build Cluckwork.sln 0 warnings
Application.Tests Architecture + TenantBypass + Documentation + ImagePin 474/474 (main 474)
Application.Tests Farm/Account/Currency/Logo/Banner classes; Domain.Tests 106/106; 495/495
ServingGuardCoverageTests (Farm's registration is its sentinel), TrackedMutationReadTests, AccountSuspensionTests 7/7, 2/2, 16/16

Tenant-bypass registry, before and after (#632 keys)

Rows were parsed from BypassAllowList.cs and FilterFreeSetSites.cs at base ccb55584 (after Access's re-keys) and at head 31b4b347; base rows were mapped through the move's type and path table.

Check Result
Row counts allow-list 40 → 40, filter-free 36 → 36
Allow-list, every row after the map, all fields identical; Hash multiset identical: no allow-list hash changed (Farm has no allow-list row; none was re-keyed)
Filter-free, all fields as multisets base rows with only the 6 documented re-keys applied equal the head rows: no Symbol, Set or Reason changed, and no other Signature
Re-keyed rows 6 filter-free Signatures, all in the re-key commit with the namespace-only proof above
Live scanner vs registry TenantBypassRealTreeTests green at the head

Proofs (base ccb55584 vs head 31b4b347, re-run after the rebase)

Proof Result
EF migrations has-pending-model-changes "No changes have been made to the model since the last migration." No migration added. The only Migrations/ diff is 4 snapshot lines naming Account and UserRoleAssignment under their new namespace
EF with the base snapshot restored (ccb55584's AppDbContextModelSnapshot.cs at the head) exit 0, no pending change. With the head snapshot back and HasMaxLength(Account.MaxNameLength + 1): exit 1 ("Changes have been made to the model")
tools/schema-docs/generate.sh --check "docs/schema/ is up to date"
Ordered DI descriptors, Production/Development × serving/one-shot × Redis absent/configured (8) identical after the type map
Generated OpenAPI document (Development) identical
Exact normalized contract set per owner identical: 160 types; Farm 10, now under Modules.Farm.Contracts
Module-edge report (live edges) identical after the type map and owner-root renames
Peer-reach report identical (Farm's seam entries follow the move)
Table-owner report identical (UserRoleAssignments still Access by override; Farm's tables still Farm)
Adapter-reach report identical except the expected registration entry: FarmModuleServiceCollectionExtensions.AddFarmModule is now under the adapter root Cluckwork.Api.Modules, with empty reach and the persistence ban passing
coupling-matrix.md unchanged (CouplingMatrixRealTreeTests green)
Unused usings (IDE0005, whole solution) base 201, head 198. The codemod added none. The 4 gone were already-unused usings of emptied namespaces (Domain.Accounts, Application.Features.Accounts, Api.Endpoints.Accounts). One newly unused: global using Cluckwork.Domain.Common.Architecture; in Cluckwork.Application/GlobalUsings.cs, because Farm's were the last Application [ModuleContract] marks. The design deletes it in S10

Mutations (re-run on the rebased head in a spare worktree; each case reset, built and run against the Architecture + TenantBypass filter)

# Mutation Result Contract-set diff vs base
M1a codemod moves Contracts/UpdateFarmSettingsCommand.cs (file and namespace) back to Accounts/UpdateFarmSettings/ red AdapterReachRealTreeTests, CouplingMatrixRealTreeTests Farm −UpdateFarmSettingsCommand
M1b same file moved, .Contracts namespace kept red NamespaceFolderAgreementTests only none: the gap the folder rule closes
M2 AccountEndpoints.GetAccount injects the seam IAccountRepository (adapters never get the seam) red AdapterReachRealTreeTests, CouplingMatrixRealTreeTests —
M4 peer CreateExpenseHandler also takes IFarmLogoRepository (neither contract nor seam); built with warnings not treated as errors, because the unread parameter is otherwise a build error red PeerContractRealTreeTests —
M7 edited predicate inside a re-keyed member: RequireActiveOwnerAsync's r.Name == …Roles.Owner → …Roles.Manager red TenantBypassRealTreeTests.RealSourceTree_FilterFreeSetSitesAreStableAndClassified —
M7c control: same member, only a /* probe */ comment added inside the query green: comments are trivia, so M7's red comes from the token —

@mforce mforce added this to the Modular monolith milestone Oct 5, 2026
mforce added 6 commits October 6, 2026 01:15
…Repository.cs

move.py split: FarmLogoMetadata, FarmLogoContent and FarmBrandingHashes
leave the repository port's file, each into its own file in the same
namespace. Each declaration is a verbatim slice of the original.

Refs #1087
move.py move with the slice's table: Domain, Application and Api files go
under Modules/Farm, contract types under Contracts, with the namespace taken
from the folder. UserRoleAssignment stays in Farm (Domain/Modules/Farm/
Accounts) with its table-owner override and seam entry; the Seam strings,
edge symbols and registry rows follow the move. The current model snapshot
follows the moved entities; historical migrations and Designer files are
untouched. The rules file now names Cluckwork.Domain.Modules.Farm and
Cluckwork.Application.Modules.Farm; Implementations stay for S9.

Refs #1087
IFarmModule's comment still said adapters reach Farm through the types marked
[ModuleContract]; those marks go in this slice. It was the last such comment.

Refs #1087
…for Farm's namespace

RequireActiveOwnerAsync, CountOtherActiveOwnersAsync and DisableUserAsync
spell Cluckwork.Domain.Accounts.Roles.Owner in full inside their queries, so
their #632 token hashes follow the namespace:

  RequireActiveOwnerAsync      aed7b297 -> 71384910 (db.Roles, db.UserRoles)
  CountOtherActiveOwnersAsync  57009ecd -> b7bada95 (db.Roles, db.UserRoles)
  DisableUserAsync             9b6fec98 -> 9e5764d7 (db.Roles, db.UserRoles)

Proof, run with the real GuardScanner.QuerySignatureOf on the base and head
files: each method's whole token stream is equal after normalizing only
Cluckwork.Domain.Accounts. to Cluckwork.Domain.Modules.Farm.Accounts. (each
gains exactly four tokens). No predicate changed. The names stay fully
qualified and the hasher is unchanged; the 40 allow-list hashes are
untouched.

Refs #1087
The ten Farm contract types now sit in Modules/Farm/Contracts; the folder
makes them contract, and a type with both fails.

Refs #1087
The SPA's slug-pattern comment names Account.cs's path, and the
UserRoleAssignments table-owner override reason names the namespace its CLR
type remains in; both now name Modules/Farm/Accounts. The override itself is
unchanged.

Refs #1087
@mforce
mforce force-pushed the refactor/1087-farm-module branch from 74b1bd2 to 31b4b34 Compare October 6, 2026 01:19
@mforce
mforce merged commit 57cdbc6 into main Oct 6, 2026
19 checks passed
@mforce
mforce deleted the refactor/1087-farm-module branch October 6, 2026 01:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant