Repository navigation
Description
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)
- Add a persisted farm setting controlling plain-Worker sale allocation:
AssignedFlocksOnly— default.AllFarmFlocks— opt-in.
- Owner and Manager may change it in Farm Settings.
- The setting applies only to plain Workers. Owner, Manager, and Sales-role users always retain farm-wide FIFO allocation.
- 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.
- Trigger that warning for any assigned-stock shortfall, not only zero assigned stock.
- 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:
- Determine whether the same line/order could be fulfilled by farm-wide eligible stock under the same date, grade, quantity-available, and withdrawal rules.
- 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.
- If no, return existing
EggLot.InsufficientStock. - 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
Accountfarm settings and bumpVersionwhen changed. - Add one forward migration;
InitialCreateremains 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 +
AllFarmFlocksallocates 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
- Changing which roles may create/confirm sales.
- Letting a Worker choose a source flock per order line.
- Changing read scoping from Worker flock assignment is enforced on writes but not on reads — a restricted worker can enumerate and read unassigned flocks #388.
- Changing write-side
FlockScopeGuardbehavior for production recording.
Activity
mforce commentedon Aug 28, 2026
Review follow-up from #388 / PR #611 (Claude Opus, 2026-08-28):
AssignFlockHandlercurrently does not require the target to be a plain Worker. An Owner can assign a flock to a Sales or ReadOnly user;FlockScopeResolutionMiddlewarethen 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.
mforce commentedon Aug 28, 2026
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.
feat(sales): require a discount reason when confirming a below-list o…
feat(sales): refuse an over-ceiling confirm from a Sales user (#727) (#…