You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
test(arch): guard module-to-module calls against non-contract types #1023
Amended 2026-10-04 (#857 E2, PR #1060): E2 implements both deferred Access types claims and their independent mutation proofs. #1060 completes this issue on merge; the original body is retained below. See this comment.
Gap
The contract guards from #849 (and #851, #852) check adapters only: endpoints, CLI verbs, jobs and seeders. Nothing checks module-to-module calls. After #852, no handler outside Flock Management injects IFlockRepository or IBirdMovementRepository. But nothing stops a future peer handler from injecting one again, and CI stays green when it does.
The same holds for Finance, Farm and every later contracted module.
Why it was deferred
A constructor-parameter check over all of Cluckwork.Application is cheap. But Farm deliberately keeps IAccountRepository and Domain.Accountsoutside its contract, as the stable seam every module calls directly (#851, its 2026-09-26 audit). A blanket rule would fail on that. The ledger schema needs a per-owner opt-in, or a per-owner list of seam types peers may use, before the check can be written. Recorded as a known gap in docs/decisions/852-* (PR #1021).
Done when
module-ledger.json can declare, per owner, which of its types peer modules may reach (its contract plus any deliberate stable seam).
A guard fails when an Application handler or service in one module takes a non-contract, non-seam type of another contracted module, as a constructor parameter or a service resolution.
Each rule is mutation-proven per AGENTS.md "Writing a guard": re-injecting IFlockRepository into a Finance handler goes red, and Farm's IAccountRepository seam stays green.
PR #1033 ships the Access-independent part of this issue. That covers the seam and types ledger schema with their errors, AdapterReachScanner.ScanPeers, and PeerContractRealTreeTests over every module, replacing the Commerce-only check from #1030. It also adds Farm's seam (IAccountRepository, Domain.Accounts.Account, Domain.Accounts.UserRoleAssignment), the fixtures, and the decision record docs/decisions/1023-peer-contract-guard.md. The PR says Refs #1023, so this issue stays open for the remainder.
Remaining, after #857 E declares Access's contract:
Claim Cluckwork.Application.Common.IIdentityProvider and Cluckwork.Application.Common.IStepUpGrantService for Access through owners.Access.types. Measured on main at 7bb45cc, the claim adds 4 adapter rows (Auth Logout and StepUp, MeEndpoints.GetMe, UserEndpoints.ListUsers) and changes the coupling matrix. With a placeholder Access contract, it finds 2 violations between modules, both in ConfirmSaleHandler (IIdentityProvider and IUserRoleAssignmentRepository), and 7 adapter bypasses (Auth Login, Logout, Refresh and StepUp, GetMe, ListUsers, SimulationDataSeeder.ctor). [C] #514 slice 15: Access contract — security hold point, runs last #857 B, C and E remove all of these.
Before claiming, re-run the measurement at E's head. With the two claims in the ledger, AdapterReachRealTreeTests and PeerContractRealTreeTests must stay green.
Mutation to prove it: with the claim and Access's contract in place, adding IIdentityProvider to a Finance handler must turn PeerContractRealTreeTests red. Removing the types row must turn it green.
PR #1060 implements the remaining Access work from the 2026-10-03 handoff. It claims Cluckwork.Application.Common.IIdentityProvider and Cluckwork.Application.Common.IStepUpGrantService through owners.Access.types, with Access's final 28-entry contract. Simulation creation now uses IAccessOperations.CreateUserAsync, so its constructor no longer bypasses the claimed identity port.
Measured at E2 head 3731894a, integrated with main 20198660: the full Application suite passes 722/722; the peer walk covers 1070 members, and the adapter walk covers 402 adapters with 139 non-empty reaches. The generated matrix is current. Each claim is tested separately: a Finance member taking that port fails the named peer-contract assertion; removing only its claim makes the same probe pass. Removing either claim also fails its named ownership-presence assertion. Generic Access bypass and recursive aggregate-leak probes fail too.
Remaining: no implementation acceptance criteria remain after this PR merges. #1033 supplied the schema, peer walker, Farm seam and original mutation proof; #1060 supplies the deferred Access claims and their precondition/proofs. GitHub's closing-issues API confirms that #1060 closes #1023 as well as #857. The PR is open and awaits CI and independent Astra plus Opus security review; it has not been merged.
Deliberate limits: method-body uses, return/property/field uses and Platform-helper indirection remain the accepted limits documented in docs/decisions/1023-peer-contract-guard.md. This issue's parameter/service-resolution acceptance criteria do not promise those additional checks.
Activity
test(arch): check that Commerce reaches Egg Operations only through i…
mforce commentedon Oct 3, 2026
PR #1033 ships the Access-independent part of this issue. That covers the
seamandtypesledger schema with their errors,AdapterReachScanner.ScanPeers, andPeerContractRealTreeTestsover every module, replacing the Commerce-only check from #1030. It also adds Farm's seam (IAccountRepository,Domain.Accounts.Account,Domain.Accounts.UserRoleAssignment), the fixtures, and the decision recorddocs/decisions/1023-peer-contract-guard.md. The PR saysRefs #1023, so this issue stays open for the remainder.Remaining, after #857 E declares Access's contract:
Cluckwork.Application.Common.IIdentityProviderandCluckwork.Application.Common.IStepUpGrantServicefor Access throughowners.Access.types. Measured onmainat 7bb45cc, the claim adds 4 adapter rows (Auth Logout and StepUp,MeEndpoints.GetMe,UserEndpoints.ListUsers) and changes the coupling matrix. With a placeholder Access contract, it finds 2 violations between modules, both inConfirmSaleHandler(IIdentityProviderandIUserRoleAssignmentRepository), and 7 adapter bypasses (Auth Login, Logout, Refresh and StepUp,GetMe,ListUsers,SimulationDataSeeder.ctor). [C] #514 slice 15: Access contract — security hold point, runs last #857 B, C and E remove all of these.SimulationDataSeeder'sCreateUserAsyncontoIAccessOperations(owner decision). Otherwise the seeder becomes an adapter bypass once Access ownsIIdentityProvider.AdapterReachRealTreeTestsandPeerContractRealTreeTestsmust stay green.IIdentityProviderto a Finance handler must turnPeerContractRealTreeTestsred. Removing thetypesrow must turn it green.mforce commentedon Oct 4, 2026
Amendment from #857 E2 (PR #1060)
PR #1060 implements the remaining Access work from the 2026-10-03 handoff. It claims
Cluckwork.Application.Common.IIdentityProviderandCluckwork.Application.Common.IStepUpGrantServicethroughowners.Access.types, with Access's final 28-entry contract. Simulation creation now usesIAccessOperations.CreateUserAsync, so its constructor no longer bypasses the claimed identity port.Measured at E2 head
3731894a, integrated with main20198660: the full Application suite passes 722/722; the peer walk covers 1070 members, and the adapter walk covers 402 adapters with 139 non-empty reaches. The generated matrix is current. Each claim is tested separately: a Finance member taking that port fails the named peer-contract assertion; removing only its claim makes the same probe pass. Removing either claim also fails its named ownership-presence assertion. Generic Access bypass and recursive aggregate-leak probes fail too.Remaining: no implementation acceptance criteria remain after this PR merges. #1033 supplied the schema, peer walker, Farm seam and original mutation proof; #1060 supplies the deferred Access claims and their precondition/proofs. GitHub's closing-issues API confirms that #1060 closes #1023 as well as #857. The PR is open and awaits CI and independent Astra plus Opus security review; it has not been merged.
Deliberate limits: method-body uses, return/property/field uses and Platform-helper indirection remain the accepted limits documented in
docs/decisions/1023-peer-contract-guard.md. This issue's parameter/service-resolution acceptance criteria do not promise those additional checks.