Repository navigation
refactor(access): declare fixture contracts and preserve actors (#857 E2) - #1060
Conversation
…ntract # Conflicts: # src/Cluckwork.Application/Features/Users/IAccessLookup.cs # src/Cluckwork.Application/Features/Users/IAccessOperations.cs # src/Cluckwork.Infrastructure/Identity/AccessOperations.cs
Security review, PR #1060 (#857 E2) at
|
| Area | Result |
|---|---|
| Production reachability | Safe. IAccessSeedLookup, DemoDataSeeder and SimulationDataSeeder are registered only inside !IsProduction(), and SeedCliCommand uses GetService. FixtureReadPortIsRegisteredOnlyOutsideProduction pins all three. |
| Same email in two farms | Safe. FindUserByEmailAsync goes through AccountUserDirectory, which filters on AccountId and NormalizedEmail explicitly. ApplicationUser has no tenant filter, so that filter is the only guard. GetActorAsync filters on AccountId && Id. ActorReadsPreserve… covers both farms. |
| Disabled users | Selection skips disabled Owners (lowest Id among active Owners). The cast path still refuses disabled members. See S3 for the reread. |
| Role fabrication | Safe. Both seeders take actor.Roles from UserManager.GetRolesAsync on a fresh reread. |
| Owner selection | Lowest Id among active Owners, with disabled Owners counted separately. If the reread misses, demo returns Failed and simulation throws, and neither falls back to another actor. |
IgnoreQueryFilters |
Not used in new src code. The inlined RestrictOneWorkerAsync read matches UserRoleAssignmentRepository.ListByUserAsync exactly, and runs after tenant.Resolve (SimulationDataSeeder.cs:274), so the tenant filter applies. |
CreateUserAsync credentials |
It forwards to IdentityProvider.CreateUserAsync with mustChangePassword:false, which is the same call as before. The password still goes through UserManager.CreateAsync validation, the role is checked against Roles.Assignable, and the audit row requires an actor (#500). The fixture password comes from Simulation:CastPassword, never a literal. |
| Contract bypass | Claiming IIdentityProvider and IStepUpGrantService closes the direct route. A Finance probe and an adapter probe both go red, per the worker's mutants. Two contract ports remain wide; see S1 and S2. |
Findings
S1 (P3, latent): IAccessOperations.CreateUserAsync lets any adapter that already reaches Access create a user without step-up.
- Where:
IAccessOperations.cs:20andAccessOperations.cs:25. The port is registered unconditionally (CluckworkIdentityServiceCollectionExtensions.cs:142), so it exists in Production. - How it is exposed: interactive creation needs a fresh, single-use step-up grant (Require recent step-up authentication for privileged user administration #308/Step-up (#308) gates only Owner creation — a stolen Owner token still buys durable access #360,
CreateUserHandler.cs:21). This method skips the grant and can assign any assignable role, Owner included. - Evidence: my mutant M3 added an
IAccessOperationsparameter toUserEndpoints.CreateUser.AdapterReachRealTreeTests,PeerContractRealTreeTestsandModuleLedgerRealTreeTestsall stayed green (5/5). That happens becauseIAccessOperationsis a contract type and the endpoint row already declares Access. - Not a regression: on
main,IIdentityProviderwas a free Platform port, so this capability was wider before.RecoverAdminAsyncon the same port already has the same exposure. - Remedy: add a caller guard like
FarmDirectoryCallerTeststhat limitsIAccessOperationstoApi/CliandSimulationDataSeeder. Otherwise, state in the decision record that only review protects this port.
S2 (P3, latent): IAccessSeedLookup reads any farm's users and is in the adapter- and peer-visible contract.
- Where: the port takes an arbitrary
accountIdand never compares it withTenantContext. LikeIFarmDirectory, it reads across farms by design. - Why it is only latent: Production does not register it, so a stray endpoint fails to resolve rather than leaking data. In Development, Testing or Staging (
!IsProduction()), an endpoint or peer that takes it would return another farm's user email, disabled state and roles. - Remedy: the same caller guard as S1 (limit it to the two seeders), or one sentence in
857-access-contract.mdnaming this as a review-only boundary.
S3 (P3, parity): the Owner reread returns DisabledAt, but neither seeder checks it.
- Where:
DemoDataSeeder.cs:145-148andSimulationDataSeeder.cs:289-291. - Failure scenario: an Owner disabled between
ListUsersInRoleAsyncandGetActorAsyncis still resolved as the fixture actor.mainhas the same window, because it reused the staleApplicationUser. - Remedy: the reread now makes the fix one condition:
if (actor is null || actor.DisabledAt is not null)fails the seed. This is a non-Production verb, so it is optional.
My E1 leftovers
- S1,
nullmeaning farm-wide for an unknown or foreign user id: addressed in documentation.IAccessLookup.cs:14-15now says to pass the resolved actor or a verified tenant member, and that the read does not check membership. The decision record repeats it. The result type is unchanged, so the barenullremains (see Q3). - S2,
AccessLifecycleDependencyTestsdoes not poisonUserManager: addressed by narrowing the claim. The test is unchanged. The decision record and thesrc/AGENTS.mdrule now claim only "without Identity or Redis", which is the narrower option I offered.
Mutation spot-check
| Mutant (mine) | Result |
|---|---|
M1: drop AccountId from GetActorAsync |
Red. AccessSeedLookupTests.ActorReadsPreserve…: Assert.Null() Failure |
M2: demo resolves [Roles.Owner] instead of the actual roles |
Red. AccessSeederActorTests: collections differ |
M3: endpoint takes IAccessOperations |
Green (S1) |
All 61 of the worker's mutant logs report Failed!. The unclaimed-* controls pass on main, which is what they are meant to show. M1 and M2 repeat the worker's actor-loses-account-predicate and demo-fabricates-owner-roles and fail on the same assertions. Head runs, one class at a time under sg docker: AccessSeedLookupTests 6/6, AccessSeederActorTests 1/1, AccessSeedDependencyTests 4/4, AccessSeedOwnerFailureTests 4/4, AccessSeedAssignmentAtomicityTests 1/1, AccessLifecycleDependencyTests 7/7. Application guards (ownership claim, adapter reach, peer, module contract, compatibility, ledger, matrix) 12/12.
Code quality (P3, slice-scoped)
Thermo-nuclear
- Q1 (fix before merge): 20 adapter rows in the ledger are stale.
AdapterReachRealTreeTestsreports 20LoosenableSimulationDataSeeder.* -> Accessrows. They went stale because this PR movedSimulationOptionsandCurrentUserContextto Persistence. One of them,RolesOfAsync, names a method this PR deleted. That is why the coupling matrix drops fromA (48)toA (28). Each stale row lets that seeder member start using Access types later without failing any check. Prune them; AGENTS.md says shrinking is free. - Q2 (option for [C] #514 slice 16: Platform composition, jobs, CLI and seeder conversion #858): duplicated Owner selection. Both seeders still carry their own copy of
FindOwnerAsync, then callGetActorAsync. A singleIAccessSeedLookup.SelectOwnerAsyncreturning(AccessActor?, disabledCount)would remove both copies and the separate reread. That is reasonable to defer to [C] #514 slice 16: Platform composition, jobs, CLI and seeder conversion #858, because the design fixes the reread at its original position for SQL-trace parity. - Q3 (option): nullable fields that cannot be null.
AccessActor.EmailandAccessUserSummary.Emailarestring?, butAspNetUsers.EmailisNOT NULL(migrationRequireUserIdentityColumns). Declaring themstringremoves three!operators. - No file crosses 1,000 lines because of this PR:
SimulationDataSeeder.cswas already 2,641 lines, and this PR made it shorter. No conditionals were added to shared paths.
Ponytail
module-ledger.jsonadapters:delete:the 20 LoosenableSimulationDataSeeder -> Accessrows (Q1).AccessSeedAssignmentAtomicityTests.cs:L60-80andAccessSeederActorTests.cs:L20-40:reuse:the same three-Owner setup loop appears in both. Move it to one helper inIntegrationTests/Infrastructure.AccessSeedAssignmentAtomicityTests.cs:L11:shrink:theMicrosoft.AspNetCore.Identityusing sits afterMicrosoft.Extensions.*. Sort it.
net: about -40 lines possible.
Evidence: /home/mforce/.cluckwork-slices/reviews/1060-opus-evidence/ (head runs, mut-M1..M3*.log, loosenable.log).
|
Verdict: APPROVE E2 at The requested E1 leftovers are:
The 28-entry contract is complete for the agreed design and contains no aggregate or persistence leak. The assignment repository remains outside it. Both Common identity ports are independently Access-owned and outside the contract. Recursive-contract, peer, adapter, compatibility and generated-matrix checks pass. The matrix matches regeneration; Access adapter reach changes from 48 to 28 without adding or widening a peer W/R edge. Five Access compatibility rows expire at #858, and the unchanged filtered Flocks LEFT JOIN expires at #859. Live #1023/#858 amendments record those limits. The existing method-body, return/property/field and Platform-helper gaps remain explicitly outside #1023's guarantee. Seeder behavior is preserved. The fixture lookup and both seeders are absent from Production registration. Demo's real read graph constructs neither IdentityProvider nor Redis. Independent tests cover the lowest active Owner, every actual role, same-email cross-farm actor reads, the registered normalizer, missing/failed rereads, cancellation, fixture creation, exact validation and assignment/audit atomicity. The simulation assignment retains the ordered untracked query and one save after its Owner-authored audit. Context/options bodies differ only by namespace. I compared the supplied base/head snapshots directly: demo's 977 and simulation's 453 action/actor rows, worker rotation and the complete simulation manifest match. All 42 request artifacts match byte-for-byte. After normalizing only SQL parameter names, each seeder adds exactly the documented account/id-scoped Owner reread: demo 4389→4390 statements, simulation 1772→1773. The successful simulation fixture also passed its 39 existing cases independently, including counts, attribution, rotation, manifest and rerun checks. #1039's three query-warning checks pass; the integration initializer enables that policy for these seeder runs too. Independent mutation spot-checks:
Verification: 75 distinct unchanged-head tests passed across 15 targeted classes, zero skips. Six red mutations and two green ownership controls were reproduced; affected checks passed again after restoration. The UserManager probe's 7/7 green result is a confirmed guard limitation, not mutation coverage. Tests ran one class at a time with Applied All scratch changes were restored and the checkout was clean before posting. No implementation fix, commit or push was made. Reproduction scripts, TRX/logs, comparisons and the detailed quality/verification reports are in |
|
Reply to Astra's review, addressed in The lifecycle builder now poisons After restoration, Combined fix validation: 722/722 Application tests; 87/87 cases across nine serial targeted classes; warning-free solution build; 66 named assertion-red mutation records. The PR body has the updated change map and quoted mutation table. Exact probe/control TRX and the final results are in |
|
Reply to Opus's review, addressed in Q1: removed exactly the 20 observed stale simulation→Access ceilings, including S1/S2: the decision record explicitly says only review restricts operations callers to operator CLI/simulation and fixture lookup callers to the two seeders. It names Production operations' step-up bypass and the fixture port's cross-farm reads outside Production. No caller guard is added. The lifecycle guard also poisons UserManager; the exact reviewer factory mutation now fails all six real-verb cases with Combined fix validation: 722/722 Application tests; 87/87 cases in nine serial targeted classes; zero build warnings/errors; 66 named assertion-red mutations; unchanged frozen B/D traces. The role helper is inlined with its exact query body and unchanged TSV query tokens. The PR body records the final change map, properties and quoted failures. Evidence: |
|
Verdict: APPROVE Opus Q1 was valid. My first pass missed the unused adapter ceilings because the normal guard reports
Independent validation: 25 passing cases across seven targeted classes, zero skips, plus the expected six assertion failures from the UserManager probe. Tests ran serially, one class at a time, with All temporary test edits were restored. The checkout was clean at the reviewed head before posting. No product code, commit or push was made. Scripts, mutation diff, TRX/logs, byte comparisons and matrix hashes are retained in |
Access now declares its final 28-type contract. Demo and simulation reconstruct real actors through a fixture-only read port; simulation creates cast users through Access operations. The two Common identity ports become Access-owned, closing the deferred #1023 bypass.
This is E2, following #1055 (E1). Review the new ports and ledger first, then the two small seeder diffs. Session/profile minting remains the A–D implementation; the requested deeper session reshape needs its own design.
Change map
The contract contains seven ports, nine values and twelve commands.
IUserRoleAssignmentRepositoryis absent because it exposes an aggregate. Platform→Access adapter reach falls from A48 to A28; no peer W/R edge is added or widened. The generated matrix is regenerated withCLUCKWORK_REGENERATE_MATRIX=1. The 20 stale simulation→Access adapter ceilings, including deletedRolesOfAsync, are pruned; the final report has zeroLoosenableentries. Five Access compatibility rows remain for #858: three AspNetRoles prerequisites, the AspNetUsers total count and the assignment write. The repository's one filtered Flocks LEFT JOIN is re-dated to #859. The two seeders, persistence registration and moved options/context are left ready for #858 P5; no fixture configuration key changes.Properties to refute
GetAssignedFlocksAsyncdocuments that its caller must pass the resolved actor's id or a verified tenant member; zero visible assignments also applies to an unknown/foreign id. Null is unrestricted and read failures propagate. The #1023 walker still has its documented method-body, return/property/field and Platform-helper limits.IAccessOperationsis registered in Production and bypasses interactive step-up; only review restricts it to operator CLI/simulation callers.IAccessSeedLookupaccepts explicit cross-farm account ids outside Production; only review restricts its callers to the two seeders. No new caller guard is added.Validation
20198660plus E2. Measured baseline at7014566cand E1: 704/704; E2 before test(arch): match build symbols and reject inactive source #1056: 706/706.Expected: 0, Actual: 1; the restored guard passes 7/7. The pruned ceiling has its own before-green/after-red probe. Identity/Redis/cache and role-predicate mutants were refreshed after inlining. All 16 architecture mutations and both independent claim-removal green controls were repeated after integrating test(arch): match build symbols and reject inactive source #1056. The main merge changed no E2 runtime source; the subsequent fix only inlines the unchanged effective-role query body.Baseline/head seeder snapshots match: demo has exactly 977 audit rows (Customer.Create 3, DailyEntry.Create 481, DailyEntry.Submit 480, Flock.BirdMovement 1, Flock.Create 3, Product.Create 3, SalesOrder.AddItem 3, SalesOrder.Confirm 1, SalesOrder.Create 2), all signed by its Owner. Simulation has exactly 453 audit rows with the same complete action/actor groups and worker/submitter rotation, and six products.
The fixed-clock simulation manifest matches completely: 2 accounts; 10 users (1 Owner, 1 Manager, 1 Sales, 3 Workers, 4 ReadOnly); 101 customers; 102 flocks (100 active/1 depleted/1 archived); 55 bird movements; 24 entries (4 draft/10 submitted/10 locked); 100 egg lots; 6 orders (2 draft/4 confirmed); 1 payment; 2 inventory items/lots; 122 inventory movements (2 purchase/8 usage/111 adjustment/1 discard); 8 feed and 8 water rows; 2 expense categories/5 expenses. Anchor, completion and fingerprint match. Cross-day/partial/changed-definition siblings pass independently too.
Full seeder SQL differs only by the explicit account-scoped Owner reread at statement six: demo 4389→4390 and simulation 1772→1773. Only parameter names are normalized. The 42 B SQL/HTTP artifacts remain identical; the D verb/purge artifacts match after only timestamp/elapsed normalization. Context/options bodies match main after only namespace replacement.
The #1023 amendment records that #1033 plus E2 completes its acceptance criteria. The #858 handoff records 37 remaining rows (29 simulation, 8 demo), including the five Access rows and P5's assignment operation. Both issue bodies retain their original history.
Quality and deslop record
Ran deslop, pstack:thermo-nuclear-code-quality-review, ponytail-review and pstack:make-pr-easy-to-review myself. The read implementation is 36 lines and reuses the existing directory/normalizer. Simulation shrinks 2644→2641 lines; demo grows 427→429; no new source file reaches 1000 lines. Removed the redundant roles-copy helper, single-caller effective-role forwarder and implementation dependencies. Both rekeyed TSV sites retain query token
4adcdb84and their rationale. Kept the existing compact single-table ledger arrays and ordinary Common import. No cache, lazy factory, service location or fallback actor is added. Ponytail: Lean already. Ship.Opus E1 S1 is addressed by the assignment membership precondition comment. Lifecycle dependency guards now poison UserManager as well as IdentityProvider/Redis. The exact Astra factory probe is assertion-red; no lifecycle constructor dependency was added. The optional E1 helper-inline suggestion is implemented with the query body, predicates and cancellation unchanged.
E2 changes SimulationOptionsBindingTests only by its namespace import. The approved review round adds UserManager poison to AccessLifecycleDependencyTests and renames its theory; all seven cases and their assertions stay intact. E1's four separately approved mechanical edits were disclosed in #1055: decorator forwarder deletion in MustChangePasswordGateTests and StepUpAuthTests, Users imports in AccountProvisioningTests and TwoFarmIsolationMatrixTests. None of their assertions changed.
Local evidence:
/home/mforce/.cluckwork-slices/reviews/857-E2-evidence/; layered quality record:/home/mforce/.cluckwork-slices/reviews/857-E2-quality/. The initial tests-first commit is e245a8b. Astra approved3731894a; Opus found no blocking security defect at that head. The owner-requested combined fix addresses Q1, the UserManager guard, the role forwarder and the documented caller boundaries. S3/Q2/Q3 behavior remains unchanged; the final delta remains at the coordinator’s security hold point.66 independently restored assertion-red mutations
Every row ran its named test and failed an assertion. Compiler/environment failures are excluded. The table quotes an excerpt of the recorded failure; full messages and TRX are retained locally.
access-contract-erasedAccessOwnershipClaimTests.CommonIdentityPortRemainsOwnedByContractedAccess(type: "Cluckwork.Application.Common.IStepUpGrantService")actor-cancellation-droppedAccessSeedLookupTests.SeedReadsPropagateCancellationactor-loses-account-predicateAccessSeedLookupTests.ActorReadsPreserveAccountDisabledStateAndEveryActualRoleactor-loses-disabled-stateAccessSeedLookupTests.ActorReadsPreserveAccountDisabledStateAndEveryActualRoleactor-truncates-actual-rolesAccessSeedLookupTests.ActorReadsPreserveAccountDisabledStateAndEveryActualRoleaggregate-dto-propertyModuleContractRealAssemblyTests.RealLedger_EveryContractTypeIsFreeOfPersistenceAndAggregatesaggregate-on-contractModuleContractRealAssemblyTests.RealLedger_EveryContractTypeIsFreeOfPersistenceAndAggregatesassignment-before-order-lockConfirmSaleOrderBoundaryTests.ConfirmReadsRoleAndAssignmentsAfterTheOrderLock(disableWorker: True)assignment-flock-name-corruptSimulationSeederTests.SimulationSeed_RestrictedWorkerAssignment_PreservesActorAndAuditDetailsassignment-implementation-removedCompatibilityExceptionRealTreeTests.RealSourceTree_EveryCompatibilityExceptionIsRegisteredassignment-owner-changedAccessSeedAssignmentAtomicityTests.FailedAssignmentAuditLeavesNoCommittedAssignmentOrCompletionSignalassignment-saved-before-auditAccessSeedAssignmentAtomicityTests.FailedAssignmentAuditLeavesNoCommittedAssignmentOrCompletionSignalcache-assignmentsAccessAuthorizationContractTests.AssignmentReadObservesIndependentCommitInTheSameScopeclaim-removed-IIdentityProviderAccessOwnershipClaimTests.CommonIdentityPortRemainsOwnedByContractedAccess(type: "Cluckwork.Application.Common.IIdentityProvider")claim-removed-IStepUpGrantServiceAccessOwnershipClaimTests.CommonIdentityPortRemainsOwnedByContractedAccess(type: "Cluckwork.Application.Common.IStepUpGrantService")compat-DemoDataSeeder-MissingBaseDataAsyncCompatibilityExceptionRealTreeTests.RealSourceTree_EveryCompatibilityExceptionIsRegisteredcompat-SimulationDataSeeder-ComputeCountsAsyncCompatibilityExceptionRealTreeTests.RealSourceTree_EveryCompatibilityExceptionIsRegisteredcompat-SimulationDataSeeder-FindOwnerAsyncCompatibilityExceptionRealTreeTests.RealSourceTree_EveryCompatibilityExceptionIsRegisteredcompat-SimulationDataSeeder-MissingBaseDataAsyncCompatibilityExceptionRealTreeTests.RealSourceTree_EveryCompatibilityExceptionIsRegisteredcompat-SimulationDataSeeder-RestrictOneWorkerAsyncCompatibilityExceptionRealTreeTests.RealSourceTree_EveryCompatibilityExceptionIsRegisteredcompat-UserRoleAssignmentRepository-ListByNameByUserAsyncCompatibilityExceptionRealTreeTests.RealSourceTree_EveryCompatibilityExceptionIsRegisteredcompletion-before-validationAccessSeedAssignmentAtomicityTests.FailedAssignmentAuditLeavesNoCommittedAssignmentOrCompletionSignaldemo-fabricates-owner-rolesAccessSeederActorTests.DemoSelectsTheLowestActiveOwnerAndResolvesTheirEntireRoleSetdemo-null-owner-fallbackAccessSeedOwnerFailureTests.MissingOrFailedOwnerReadNeverResolvesAnActorOrCertifiesFixtures(simulation: False, throwRead: False)demo-selects-disabled-ownerAccessSeederActorTests.DemoSelectsTheLowestActiveOwnerAndResolvesTheirEntireRoleSetdemo-selects-highest-ownerAccessSeederActorTests.DemoSelectsTheLowestActiveOwnerAndResolvesTheirEntireRoleSetdisabled-cast-reusedSimulationDisabledCastMemberTests.SimulationSeed_WhenASeededCastMemberIsDisabled_RefusesTheRerundisplay-role-instead-of-live-roleAccessAuthorizationContractTests.AssignmentAdmissionRefusesDisabledAndMultipleRoleTargets(disabled: True)drop-active-member-predicateConfirmSaleOrderBoundaryTests.ConfirmReadsRoleAndAssignmentsAfterTheOrderLock(disableWorker: True)drop-role-account-predicateAccessLookupTests.GetEffectiveRole_AnswersOnlyForTheAccountItIsAskedAbouteffective-role-before-proofAccessAuthorizationContractTests.MissingAssignmentProofReadsNoTargetsForKnownOrUnknownUsersemail-cancellation-droppedAccessSeedLookupTests.SeedReadsPropagateCancellationfinance-IIdentityProviderPeerContractRealTreeTests.EveryModule_ReachesAContractedPeerOnlyThroughItsContractOrSeamfinance-IStepUpGrantServicePeerContractRealTreeTests.EveryModule_ReachesAContractedPeerOnlyThroughItsContractOrSeamfixture-cancellation-droppedAccessSeedLookupTests.FixtureCreationAuthenticatesWithoutPasswordChangeAndWritesOnce(role: "Manager")fixture-cast-count-changedSimulationSeederTests.SimulationSeed_CastCountsAreTheOnesThePersonaAssertionsAssumefixture-creation-twiceAccessSeedLookupTests.FixtureCreationAuthenticatesWithoutPasswordChangeAndWritesOnce(role: "Manager")fixture-password-changedAccessSeedLookupTests.FixtureCreationAuthenticatesWithoutPasswordChangeAndWritesOnce(role: "Manager")fixture-read-in-productionAccessSeedDependencyTests.FixtureReadPortIsRegisteredOnlyOutsideProduction(environment: "Production", expected: False)fixture-requires-password-changeAccessSeedLookupTests.FixtureCreationAuthenticatesWithoutPasswordChangeAndWritesOnce(role: null)generic-adapter-access-bypassAdapterReachRealTreeTests.RealSourceTree_EveryAdapterReachIsDeclaredgeneric-finance-access-bypassPeerContractRealTreeTests.EveryModule_ReachesAContractedPeerOnlyThroughItsContractOrSeamidentity-in-lifecycleAccessLifecycleDependencyTests.RealLifecycleVerbNeverConstructsIdentityRedisOrUserManager(verb: "rename-account", poisonRedis: True)identity-in-seed-readAccessSeedDependencyTests.DemoSeederReadGraphNeverConstructsIdentityOrRedis(poisonRedis: True)lifecycle-usermanager-factoryAccessLifecycleDependencyTests.RealLifecycleVerbNeverConstructsIdentityRedisOrUserManager(verb: "reactivate-account", poisonRedis: False)members-cancellation-droppedAccessSeedLookupTests.SeedReadsPropagateCancellationnormalizer-replaced-with-uppercaseAccessSeedLookupTests.EmailReadUsesTheRegisteredIdentityNormalizerpromoted-worker-reusedSimulationPromotedWorkerTests.SimulationSeed_WhenTheRestrictedWorkerIsPromoted_RefusesTheRerunpruned-seeder-access-reintroducedAdapterReachRealTreeTests.RealSourceTree_EveryAdapterReachIsDeclaredredis-in-lifecycleAccessLifecycleDependencyTests.RealLifecycleVerbNeverConstructsIdentityRedisOrUserManager(verb: "rename-account", poisonRedis: True)redis-in-seed-readAccessSeedDependencyTests.DemoSeederReadGraphNeverConstructsIdentityOrRedis(poisonRedis: True)role-before-order-lockConfirmSaleOrderBoundaryTests.ConfirmReadsRoleAndAssignmentsAfterTheOrderLock(disableWorker: True)role-members-hide-disabledAccessSeedLookupTests.RoleMembersIncludeDisabledUsersAreAccountScopedAndOrderedByIdrole-members-reverse-id-orderAccessSeedLookupTests.RoleMembersIncludeDisabledUsersAreAccountScopedAndOrderedByIdsecond-actor-instanceAccessAuthorizationContractTests.ScopedActorAndLookupShareStateAndRemainIndependentsimulation-disabled-ownerAccessSeedAssignmentAtomicityTests.FailedAssignmentAuditLeavesNoCommittedAssignmentOrCompletionSignalsimulation-highest-ownerAccessSeedAssignmentAtomicityTests.FailedAssignmentAuditLeavesNoCommittedAssignmentOrCompletionSignalsimulation-null-owner-fallbackAccessSeedOwnerFailureTests.MissingOrFailedOwnerReadNeverResolvesAnActorOrCertifiesFixtures(simulation: True, throwRead: False)simulation-owner-literal-roleAccessSeedAssignmentAtomicityTests.FailedAssignmentAuditLeavesNoCommittedAssignmentOrCompletionSignalsingleton-actorAccessAuthorizationContractTests.ScopedActorAndLookupShareStateAndRemainIndependentsingleton-lookupAccessAuthorizationContractTests.ScopedActorAndLookupShareStateAndRemainIndependentskip-exact-count-validationAccessSeedValidationTests.PollutedFixtureFailsExactValidationWithoutCompletionCertificationswallow-assignment-failureAccessAuthorizationContractTests.AssignmentReadFailurePropagatesInsteadOfGrantingUnrestrictedScopetarget-before-proofAccessAuthorizationContractTests.MissingAssignmentProofReadsNoTargetsForKnownOrUnknownUsersworker-stored-as-roleSimulationCrossDayRerunTests.Rerun_AfterUtcDayRollover_ConvergesToAlreadySeeded_WithUnchangedFingerprintAndNoDuplicateRowswrong-role-cast-reusedSimulationReconfiguredCastTests.SimulationSeed_WhenACastPersonaLostItsRole_FailsNamingTheRoleE2 also completes #1023: #1033 supplied its schema, peer guard and Farm seam; this PR supplies both Access claims, the simulation prerequisite, current measurement and independent claim mutations. Its documented guard limits remain accepted. #858 P5 owns the five remaining fixture reads/write; #859 owns the filtered Flocks join.
Closes #1023
Closes #857