Skip to content

[C] #514 slice 13: General Inventory contract and the flock-eligibility read #855

Closed

Description

@mforce

Amended 2026-10-02 (#852, PR #1021): the three usage handlers now read flock eligibility through IFlockLookup, with the feed-usage order unchanged; IInventoryModule remains. See this comment.

Important

Track C is unscheduled. These slices move production code, and the 2026-08 design's own status
line still governs: "proposed architecture; no production refactor is authorized by this
document."
Filed so the analysis is tracked work rather than a comment, not as a commitment to
run it.

The 2026-09-14 re-plan
recommends gating Track C on evidence from Tracks A and B: if the #842 ratchet fires repeatedly in
real pull requests, these become worth their cost; if it stays quiet, they do not. Track C is
57–95 focused engineering days and produces no user-visible change.

Read the re-plan before picking any of these up. Several assumptions in the 2026-08 plan are
corrected there.

Inventory items, lots, movements, feed usage and water usage behind a contract.

Scope

  • IInventoryModule over purchase, adjust, consume, feed usage and water usage.
  • Calls Flock Management's eligibility read, not its entities or repositories. The risk this
    slice carries is importing Flock instead of asking a question about it.
  • Calls Farm for the currency snapshot.

The ordering detail that must not move

RecordFeedUsage locks the inventory item first, then — still inside that same transaction —
evaluates flock eligibility, then reads lots. The check must stay inside the transaction and after
the item lock.

Moving it to a precondition before the transaction opens would widen the race, not close it.
Today's shape deliberately shrinks a concurrent archive/deplete race to the commit itself, and leaves
the flock row unlocked on purpose: a same-day deplete racing a same-day feed is business-valid either
way, because the birds ate before they left.

Done when

Unedited and green: backdated FIFO consumption, insufficient-stock rollback, concurrent lot
consumption, flock eligibility behaviour, currency handling, tenant and Version tests, API and SPA
contracts. One inventory transaction retained. EF model digest identical.

Explicitly not in this slice

Flock internals. Egg stock — that is Egg Operations' ledger and a different FIFO.

Activity

  1. added this to the Modular monolith milestone on Sep 14, 2026
  2. added
    sliceThin vertical work item
    area:apiAPI/endpoint layer
    size:MA day or two; migration or a multi-state UI
    epic-514Modular monolith architecture (#514)
    on Sep 14, 2026
  3. changed the title [-]#514 slice 13: General Inventory contract and the flock-eligibility read[/-] [+][C] #514 slice 13: General Inventory contract and the flock-eligibility read[/+] on Sep 14, 2026
  4. added
    track:C#514 Track C — moves production code; UNSCHEDULED, needs authorisation
    on Sep 14, 2026
  5. mforce commented on Sep 26, 2026

    @mforce
    OwnerAuthor

    Audit 2026-09-26, against main at e47288c

    No change needed. The ordering this slice says must not move is intact in RecordFeedUsageHandler: the inventory item is locked first (:67), flock eligibility is evaluated next (:89), and the FIFO lots are read last (:107), all inside the same transaction.

    One detail worth carrying into the contract design. There are also two flock reads before the transaction opens: the flock-scope guard at :41 and a flock lookup for the link at :55. So the Inventory contract needs a flock-eligibility read in two positions, pre-transaction and in-transaction, not one. The slice's prose describes only the in-transaction one, which is the one with the ordering constraint, but an implementer reading only that will miss the other two call sites.

    Census unchanged: 32 files, 5 tables, three outgoing edges (Egg Operations, Farm, Flock Management, all R), zero incoming.

  6. mforce commented on Oct 2, 2026

    @mforce
    OwnerAuthor

    Amendment from #850 (PR #1013)

    What shipped. module-ledger.json now has a compatibilityExceptions section. CompatibilityExceptionRealTreeTests fails CI on any read of a contracted module's tables that is neither allowed by structure nor registered. One row names this issue as its deletion trigger:

    • Cluckwork.Infrastructure.Repositories.CurrencyBoundRowProbe.AnyAsync reaches Finance through db.Expenses. Its owner is Farm, because the currency lock is Farm's rule.

    What this issue now owns. The probe also reads Commerce (SalesOrders, Payments, Products) and General Inventory (InventoryLots, FeedUsages, InventoryItems) tables. It can move behind module contracts only once the last of those modules has one, and this slice is that one. When this slice declares owners.GeneralInventory.contract, the guard applies to General Inventory's tables too: the probe's General Inventory reads, and any other Platform reader of those tables, become rows this slice must register or remove. Deleting the probe's db.Expenses read makes the existing row stale, so remove the row in the same PR. The rule is in docs/decisions/850-compatibility-exceptions.md.

  7. mforce commented on Oct 2, 2026

    @mforce
    OwnerAuthor

    Note from the Farm contract slice (#851, PR #1015): the locked currency snapshot did not move behind IFarmModule. Following the 2026-09-26 audit on #851, IAccountRepository and Domain.Accounts stay the stable account seam that peer modules call directly. So "Calls Farm for the currency snapshot" here means calling IAccountRepository.GetCurrentSharedLockedAsync inside the write transaction, as today (#162 FOR SHARE). It does not mean a Farm contract method. Rationale: docs/decisions/851-farm-contract.md.

  8. mforce commented on Oct 2, 2026

    @mforce
    OwnerAuthor

    Amendment from #852 (PR #1021). That PR ships part of this issue's scope. The body above is left as written.

    Shipped:

    • "Calls Flock Management's eligibility read, not its entities or repositories." RecordFeedUsageHandler, RecordWaterUsageHandler and UpdateWaterUsageHandler now take IFlockLookup and read a FlockDetails copy with CanRecordProductionOn(date).
    • The feed-usage order did not move. The item lock comes first, then eligibility inside the same transaction, then lots, with the flock row unlocked.
    • The port calls the same tracked repository method, so the second, in-transaction read still sees the instance tracked by the pre-transaction read, exactly as before.
    • InventoryEndpoints.ListFeedUsage and WaterUsageEndpoints.ListWaterUsage read display names through IFlockLookup.

    Remains for this issue: IInventoryModule, the Farm currency snapshot, and CurrencyBoundRowProbe (a #850 row with deleteWhen: #855). The unedited-test acceptance criteria are unchanged.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:apiAPI/endpoint layerepic-514Modular monolith architecture (#514)priority:tier4Deferred or speculativesize:MA day or two; migration or a multi-state UIsliceThin vertical work itemtrack:C#514 Track C — moves production code; UNSCHEDULED, needs authorisation

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions