Skip to content

Configurable Worker sales allocation scope by flock assignment #612

Closed

Description

@mforce

Context

Discovered during #388 / PR #611 review. #388 scopes a restricted Worker's reads to assigned flocks, but Workers are also intentionally allowed to create and confirm sales (AuthPolicies.SalesFlow, #73 principle). Sale confirmation allocates egg lots FIFO without asking the operator to choose a flock.

PR #611 briefly applied flock scope to EggLotRepository.GetAvailableFifoLockedAsync, which would make a restricted Worker see false EggLot.InsufficientStock whenever assigned-flock stock is insufficient even though the farm has enough stock elsewhere. #388 will preserve current main behavior (farm-wide FIFO allocation) and defer configurable sales allocation to this issue.

Owner decisions (2026-08-27)

  1. Add a persisted farm setting controlling plain-Worker sale allocation:
    • AssignedFlocksOnly — default.
    • AllFarmFlocks — opt-in.
  2. Owner and Manager may change it in Farm Settings.
  3. The setting applies only to plain Workers. Owner, Manager, and Sales-role users always retain farm-wide FIFO allocation.
  4. A Worker whose assigned-flock stock cannot fulfill the order must receive a specific warning when farm-wide stock could fulfill it: explain that an Owner/Manager can allow selling from other flocks.
  5. Trigger that warning for any assigned-stock shortfall, not only zero assigned stock.
  6. If farm-wide stock is also insufficient, keep the normal insufficient-stock error.

Required behavior

Allocation decision

At confirm time, derive effective allocation scope from both the actor and the farm setting:

Actor Farm setting FIFO candidate lots
Owner / Manager / Sales either all account/farm lots
Plain Worker with zero assignment rows or a farm-wide assignment row either all account/farm lots (existing unrestricted semantics)
Restricted plain Worker AssignedFlocksOnly assigned flocks only
Restricted plain Worker AllFarmFlocks all account/farm lots

Do not infer role from the setting or from assignment presence. Use the same effective-role semantics as AuthPolicies/CurrentUserContext.

Insufficient assigned stock discriminator

For AssignedFlocksOnly, if scoped FIFO cannot fulfill a line:

  1. Determine whether the same line/order could be fulfilled by farm-wide eligible stock under the same date, grade, quantity-available, and withdrawal rules.
  2. If yes, return a distinct stable error code (name during design) whose user-facing message says the Worker is limited to assigned-flock stock and an Owner/Manager can enable cross-flock selling in Farm Settings.
  3. If no, return existing EggLot.InsufficientStock.
  4. The probe must not allocate, mutate, or change lock ordering. Design the concurrency/lock semantics explicitly; do not issue an unlocked preflight that can make a promise the locked allocation immediately contradicts.

Settings surface

  • Add the setting to Account farm settings and bump Version when changed.
  • Add one forward migration; InitialCreate remains frozen (feat(eggs): make cracked and dirty eggs sellable stock via condition grades (#396) #407).
  • Update Account/Farm Settings GET + PUT contracts, validators/handlers, API DTOs, generated client types, and SPA Settings UI.
  • UI copy must explain both choices and identify that only plain Workers are affected.
  • Update specs/product/GLOSSARY.md, SPA Help/in-app glossary, and all supported locales (en/es/tl).

Acceptance criteria

  • New farms/default reference account use AssignedFlocksOnly.
  • Owner and Manager can switch the setting; other roles cannot.
  • Plain restricted Worker + default setting allocates only assigned-flock lots.
  • Same Worker + AllFarmFlocks allocates across all farm flocks.
  • Owner, Manager, and Sales-role confirmation remains farm-wide under both setting values.
  • Zero-assignment and farm-wide-assignment Workers remain farm-wide under both values.
  • Assigned stock insufficient + farm-wide sufficient returns the distinct admin-option warning; no partial allocation persists.
  • Farm-wide insufficient returns existing EggLot.InsufficientStock.
  • Withdrawal/future-production eligibility and canonical FIFO lock order remain unchanged.
  • Parallel confirmations preserve pessimistic-lock correctness and never over-allocate.
  • Migration + docs/schema/ regenerated and checked.
  • Settings SPA, GLOSSARY, Help, en/es/tl, and SPA UI verification track: Playwright E2E smoke + canary-under-load over the #243 sim fixture #277 simulation E2E are updated.
  • Mutation checks independently prove: role bypass, both setting branches, zero/farm-wide assignment behavior, warning discriminator, and farm-wide-insufficient fallback.

Non-goals

Activity

  1. mforce commented on Aug 28, 2026

    @mforce
    OwnerAuthor

    Review follow-up from #388 / PR #611 (Claude Opus, 2026-08-28): AssignFlockHandler currently does not require the target to be a plain Worker. An Owner can assign a flock to a Sales or ReadOnly user; FlockScopeResolutionMiddleware then narrows that user's reads because it carves out only Owner/Manager. Before #388 the row was inert for those roles. This is fail-closed (no leak), but produces inconsistent behavior: Sales confirmation remains farm-wide while Sales stock reads can be narrowed; ReadOnly can unexpectedly lose stock/report visibility.

    #612 already decides the configurable sales policy applies only to plain Workers and Sales-role users remain farm-wide. Its design must therefore explicitly settle the assignment surface too: either reject flock assignments for non-Worker targets, or make read/sales scope resolution ignore assignment rows for Sales/ReadOnly. Add role-pair tests for Owner/Manager/Sales/ReadOnly/Worker so the setting and assignment semantics cannot drift.

  2. mforce commented on Aug 28, 2026

    @mforce
    OwnerAuthor

    Additional shipped baseline to design against (PR #611 review round 3): after #388, a restricted Worker's stock/list reads are assignment-scoped, while sale confirmation deliberately remains farm-wide until #612 lands. Reachable symptom: the Worker may see 100 eggs available in assigned flocks, confirm a 500-egg order, and succeed because farm-wide FIFO finds the other 400. This is owner-approved temporary behavior, not a leak.

    #612's UI/error design must make that transition coherent in both setting modes and must not assume today's stock screen and allocation candidate set agree for restricted Workers.

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

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions