Skip to content

refactor(arch): close the Platform composition slice - #1066

Merged
mforce merged 2 commits into
mainfrom
chore/858-p8-ledger-end-state
Oct 4, 2026
Merged

mforce merged 2 commits into
mainfrom
chore/858-p8-ledger-end-state

Conversation

@mforce

@mforce mforce commented Oct 4, 2026 •

Copy link
Copy Markdown
Owner

Closes #858

#858 P8, the last slice. It closes the Platform composition slice of epic #514 Track C and records the end state.

Change map (who calls whom)

BEFORE #858 (main at 02e8a633)                  AFTER P8
----------------------------------------------  ----------------------------------------------
compatibilityExceptions: 35 rows name #858      compatibilityExceptions: 0 rows name #858
  (+5 Access rows from #857 E2)                   1 row left: UserRoleAssignmentRepository
                                                  .ListByNameByUserAsync -> Flocks (#859)

SimulationDataSeeder ──db.<Set>──▶ 7 modules    SimulationDataSeeder ──▶ I<Module>Module (writes)
DemoDataSeeder       ──db.<Set>──▶ 5 modules                         ──▶ I<Module>Fixture (reads,
                                                                         probes, counts, purges,
                                                                         flock assignment)
                                                DemoDataSeeder       ──▶ same; cleanup purges join
                                                                         the seeder's transaction

list-accounts, lock sweep ──db.Accounts──▶ Farm  list-accounts, lock sweep, suspend/reactivate/
AccountSlugLookup.ResolveAsync ──db.Accounts──▶    rename-account, seed --farm-code
                                                  ──▶ IFarmDirectory (Farm contract); no forwarder

CluckworkFeatureServiceCollectionExtensions     Hosting/Modules/<Owner>Module… + Platform file,
  (156 regs, all owners mixed) + Program.cs       listed by AddCluckworkModules; Access in
  inline Insights/idempotency                     AddCluckworkIdentity; fixture ports only in
                                                  AddCluckworkPersistence's !IsProduction()

IRepository<T,TId> (15 interfaces)              deleted (P2); IUnitOfWork kept
Insights: facade, no ledger contract            contracted (P1)

Platform, unchanged and direct (#263/#271): migrate, healthcheck, SimulationSeedStates anchor,
idempotency purge, DurableJobWorker. persistenceForbiddenNamespaces: Cluckwork.Api.Endpoints only.

This PR's own edges: the forwarder's adapter row (AccountSlugLookup.ResolveAsync -> Farm) is deleted. SuspendAccountCliCommand, ReactivateAccountCliCommand, RenameAccountCliCommand and SeedCliCommand .RunAsync each declare Farm themselves. The coupling matrix's adapters→Farm count goes 22 → 25. No module edge is added or removed. No other slice is open on these files.

Change map (files)

File What Why
Api/Cli/{Suspend,Reactivate,Rename}AccountCliCommand.cs, SeedCliCommand.cs Call GetRequiredService<IFarmDirectory>().FindIdBySlugAsync directly Approved P8 item. FarmDirectoryCallerTests cannot follow a forwarder
Api/Cli/SuspendAccountCliCommand.cs AccountSlugLookup.ResolveAsync deleted; Normalize stays Same
Application/Features/Accounts/IFarmDirectory.cs, FarmDirectoryCallerTests.cs Comments no longer name the forwarder Stale
module-ledger.json, coupling-matrix.md Adapter rows above; matrix regenerated Same
docs/decisions/858-platform-composition.md New decision record: the P1–P8 table, the rule, the end state, why not the alternatives, the guard per invariant, and the accepted limits Approved P8 item
src/AGENTS.md New #858 paragraph; drops the stale "Insights' facade is registered in Program.cs until #858 P7" Same
docs/decisions/851-farm-contract.md, docs/decisions/README.md Amendment pointer; index row The 851 amendment promised P8 would record the final state

No root AGENTS.md rule. The convention is backend-only, and the root file now indexes the scoped rule files, so src/AGENTS.md carries the one paragraph.

End-state checklist

Item State
compatibilityExceptions 0 rows name #858; the one remaining row is justified in the record and belongs to #859
Every module's contract lists its fixture port Access, Farm, Flock Management, Egg Operations, Commerce, General Inventory and Finance do. Insights has none because no seeder reads it
Farm lists IFarmDirectory yes
CLI verbs, jobs and seeders reach contracted modules only through contracts AdapterReachRealTreeTests green: 401 adapters walked, 140 rows
Loosenable empty at base and head. It stays reported, not enforced (#846); the record says so
persistenceForbiddenNamespaces unchanged (Cluckwork.Api.Endpoints)
AccountSlugLookup.ResolveAsync deleted

Parity (base main 36a87a7f)

The change inlines a one-line forwarder, so the SQL is the same call through the same scoped service.

Check Base Head
Cluckwork.Application.Tests (includes the Documentation tests) 732/732 732/732
AccountLifecycleCommandTests 24/24 24/24
AccessLifecycleDependencyTests 7/7 7/7
CliDispatcherTests 3/3 3/3
SeedCommandTests (incl. --farm-code) 8/8 8/8
ListAccountsCommandTests 8/8 8/8
ProcessRoleGuardTests / OneShotVerbMinimalConfigTests, with temporary polling passthrough (host inotify limit, as in #1065; not committed) 46/46, 20/20 46/46, 20/20
Tracked-file guards (ImagePin, SchemaDocsTests), run before committing the docs 4/4 4/4
tools/simulation/verify-harness.sh — OK (static compose-config check; it boots nothing)

#858's other "Done when" gates: the full solution, the frontend typecheck/tests/build and the Playwright quick suite run in CI on this PR (ci.yml, e2e-smoke.yml). They were not run locally. No boot guard or config key changed in any slice, so no harness or AppHost file changes.

Mutations (each applied alone, restored)

# Mutant Result
N1 Re-add a compatibilityExceptions row for a converted query (SimulationDataSeeder.EnsureExpenseAsync -> Finance, #858) red: CompatibilityExceptionRealTreeTests, "stale compatibility exception … no member by that key reads Finance's tables any more"
N2 Remove IFlockFixture from Flock Management's contract red: AdapterReachRealTreeTests + matrix, "contract bypass … DemoDataSeeder.ctor / SimulationDataSeeder.ctor -> FlockManagement through IFlockFixture"
N3 suspend-account resolves IAccountRepository (Farm seam, not contract) red: AdapterReachRealTreeTests + matrix, "contract bypass SuspendAccountCliCommand.RunAsync -> Farm through IAccountRepository"
N4 The forwarder restored and used by reactivate-account red: AdapterReachRealTreeTests, "undeclared adapter reach AccountSlugLookup.ResolveAsync -> Farm". FarmDirectoryCallerTests stays green, its documented limit; the record says the adapter guard catches it only while the row stays deleted

The integration suite ran one class at a time, as listed. The full integration suite was not run locally; CI runs it.

Deslop: removed one stray blank line in src/AGENTS.md; nothing else.

Review fix (Astra P3, fc243042): the record and src/AGENTS.md now say that only fixture implementations outside their module's namespaces go on implementations. Listing a namespace-owned one, such as Access's AccessFixture, fails CompatibilityExceptionRealTreeTests (proven by mutation). The #859 amendment is corrected the same way.

Deletes the AccountSlugLookup.ResolveAsync forwarder: the four verbs resolve
farm codes through IFarmDirectory themselves, so FarmDirectoryCallerTests
sees every caller, and the forwarder's adapter row goes. Loosenable is empty
and no compatibility row names #858. Records the end state, its guards and
its accepted limits in docs/decisions/858-platform-composition.md and
src/AGENTS.md.

Closes #858
@mforce

mforce commented Oct 4, 2026

Copy link
Copy Markdown
Owner Author

Reviewed 06a2405368c2d84145c70afee2b8937c09a0cb0e against main base 36a87a7f. One nonblocking P3 documentation finding. No introduced runtime or security defect found.

[P3] Distinguish namespace-owned fixtures from explicit implementation entries. The new decision rule and scoped AGENTS rule require every fixture's implementation on the ledger's implementations list. Access's fixtures instead belong to its declared Cluckwork.Infrastructure.Identity namespace; its list contains only UserRoleAssignmentRepository. Following the new instruction by adding AccessFixture and AccessSeedLookup makes CompatibilityExceptionRealTreeTests fail for both entries, because their reads already receive the OwnModule allowance. I reproduced this, then restored green. This affects ordinary fixture maintenance, and the #859 amendment likewise overstates that list as the complete implementation move list. Correct the prose: ports belong on contract; implementations outside the owning namespaces need the explicit list. A migration inventory must also include namespace-owned implementations, including Access's Identity classes. No production or ledger change is needed.

The four CLI replacements are exact inlinings of the deleted forwarder. Scope, Trim().ToLowerInvariant(), null handling, exit code 1, and seed's list-accounts hint remain identical. Rename still passes the same normalized source and validated destination to IAccessAccountLifecycle. Its service takes its own id/slug/Version snapshot, resolves the tenant, locks that account, and compares both slug and Version. Suspended-account lookup, session revocation, audit behavior and cross-farm targeting remain unchanged.

The ledger matches the intended end state: no #858 exception; one justified #859 filtered Flocks LEFT JOIN; all fixture ports on their contracts; 401 adapters, 140 nonempty rows and empty Loosenable. The four verbs now name IFarmDirectory directly. The persistence ban remains exactly Cluckwork.Api.Endpoints. Matrix regeneration matches the committed file, including Farm's adapter count of 25. The decision record follows the dated, accepted, No incident convention and records code facts rather than tracker status. Apart from the inventory correction above, the #859 amendment agrees with the code and the historical PR records inspected; I did not rerun earlier slices.

Independent verification: 73 baseline tests passed, one class at a time with DOTNET_USE_POLLING_FILE_WATCHER=1 under sg docker -c.

Project Classes Passed
Application FarmDirectoryCallerTests, AdapterReachRealTreeTests, CompatibilityExceptionRealTreeTests, CouplingMatrixRealTreeTests, ModuleContractRealAssemblyTests, PeerContractRealTreeTests 10
Integration AccountLifecycleCommandTests, SeedCommandTests, AccountRenameServiceTests, AccessLifecycleDependencyTests, ListAccountsCommandTests, FixturePortRegistrationTests 63

N1 independently failed on the stale SimulationDataSeeder.EnsureExpenseAsync -> Finance exception. N3 independently failed in both the adapter and matrix classes on SuspendAccountCliCommand.RunAsync -> Farm through IAccountRepository. Each affected class passed after restoration. The documentation probe also returned green after restoration. Source and built-output ledgers match; the checkout is clean. The full integration suite was not run.

The slice-scoped thermo-nuclear review found no structural regression: the changed C# files lose three lines overall, the largest is 146 lines, and no branch, wrapper, dependency or registration is added. Keeping direct resolutions makes the caller guard useful. Ponytail review: Lean already. Ship.

Local logs, mutation runner and detailed review reports are retained in /home/mforce/.cluckwork-slices/reviews/1066-06a24053-astra-evidence/. No production changes, commits or pushes.

The #858 record and src/AGENTS.md said every fixture implementation goes on
the ledger's implementations list. An implementation inside its module's
namespaces, such as Access's AccessFixture and AccessSeedLookup, already has
the own-module allowance, and listing it fails
CompatibilityExceptionRealTreeTests.

Refs #858
@mforce

mforce commented Oct 4, 2026

Copy link
Copy Markdown
Owner Author

Astra P3 (fixture implementations on implementations): fixed in fc243042 (fc24304). Docs only. No production or ledger change.

  • docs/decisions/858-platform-composition.md, The rule: the port goes on the module's contract. Its implementation goes on implementations only when it sits outside the module's namespaces, as the fixtures in Cluckwork.Infrastructure.Repositories do. Implementations inside them, such as Access's AccessFixture and AccessSeedLookup in Cluckwork.Infrastructure.Identity, already get the own-module allowance. Listing one fails CompatibilityExceptionRealTreeTests.
  • src/AGENTS.md, the [C] #514 slice 16: Platform composition, jobs, CLI and seeder conversion #858 paragraph: says the same in one clause.
  • [C] #514 slice 17: assembly split — conditional on Track A/B evidence #859 amendment: edited the same way. The move inventory now includes namespace-owned implementations such as Access's Infrastructure.Identity classes.

Evidence:

Check Result
Your case: add Cluckwork.Infrastructure.Identity.AccessFixture to Access's implementations (mutant, restored) red: CompatibilityExceptionRealTreeTests, "owner 'Access' lists implementation '…AccessFixture', which reads none of Access's tables — remove it" (its reads are [own module])
CompatibilityExceptionRealTreeTests + Documentation tests 22/22
Cluckwork.Application.Tests 732/732
Tracked-file guards (ImagePin, SchemaDocsTests) 4/4

@mforce
mforce merged commit e63ad81 into main Oct 4, 2026
19 checks passed
@mforce
mforce deleted the chore/858-p8-ledger-end-state branch October 4, 2026 19:04
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.

[C] #514 slice 16: Platform composition, jobs, CLI and seeder conversion

1 participant