Repository navigation
F15 (2/2): Feed usage + stock corrections (#66) - #70
Merged
Merged
Conversation
added 2 commits
July 17, 2026 22:07
Spec §12.4 consumption plus the correction path agreed on the issue. - FeedUsage: create-only record (date, flock, item, quantity, unit snapshot, note) with a lot-cost estimate — Σ(consumed-per-lot × that lot's unit cost), the §19 feed-cost KPI input. Repo seam rejects Update/Remove: corrections are compensating ledger rows, never edits of the usage record. - RecordFeedUsage: drains lots FIFO under the canonical (ReceivedDate, Id) FOR UPDATE lock; one Usage movement per lot drained (lot-level provenance, the #60 lesson); insufficient stock -> 422 with nothing committed. Flock gate reuses CanRecordProductionOn (depleted backfill allowed, archived never). Inactive items may still be used up — deactivation only stops new stock arriving. - InventoryLot.Adjust: signed correction bounded to [0, QuantityReceived] — below-consumed and beyond-received both refuse; extra stock is a purchase, not an adjustment. - RecordAdjustment: Adjustment (signed) or Discard (negative only) against a specific FOR UPDATE-locked lot, reason mandatory; a typo'd purchase is fixed by a compensating negative adjustment with both rows visible in the ledger. - API: POST /inventory/items/{id}/usage + /adjustments, GET /inventory/usage (flock/date filters, paged). - SPA: usage form (active-flock picker) + correction form (lot picker with remaining/received, type, mandatory reason) on the item panel. Tests: 11 new (Adjust bounds, FeedUsage guards; integration FIFO drain with per-lot movements + exact 122000 cost, insufficient 422 no-op, archived-flock 422, typo-fix adjustment, guard matrix, parallel-usage race — one winner, lot never negative, Version delta 1). 173 green. Runtime-verified: API scenario (FIFO cost math, 422/400 guards, corrections) + Playwright UI flow (usage + correction forms, ledger updates), zero console errors. Closes #66
codex P2s (no P1s), all applied: - Usage now locks the item row FIRST (item -> lots, the purchase path's order) inside its transaction — a concurrent backdated purchase could previously insert an older lot after the FIFO read. Flock lifecycle gate moved inside the transaction too (remaining same-day deplete race is business-valid and documented). - FIFO is as-of the usage date: a backdated feeding can no longer consume lots received after that day (stock that didn't exist yet). New test. - Adjustments can't predate their lot's receipt (fabricated history). New test. - Cost estimate accumulates in decimal with an explicit bound -> 422 instead of a silent long wrap/overflow 500; unit-cost minor units capped at 1e13 in the purchase/create/update validators so quantity x cost stays in range. - Usage movements carry ReferenceType/ReferenceId = FeedUsage + id (spec §12.3): several same-day feedings of one flock now reconcile to their own records. Exposed on the movements endpoint. New test. - Category gate: only Feed/Supplement/Additive items can be fed to a flock (API 422 + SPA hides the form) — packaging as feed would poison §19 KPIs. New test. - Usage POST response includes CurrencyMinorUnit (matches GET; JPY/KWD-safe). - FeedUsage.CreatedAtUtc for same-day list ordering; DailyEntryId gets a real FK; depleted flocks return to the SPA picker labeled backfill-only (the handler already allowed on-or-before-depletion dates). - Adjustment validator range check rewritten without Math.Abs (hardening; decimal's symmetric range made the reported throw unreachable). Declined as existing app-wide conventions (noted on the PR): offset pagination and FluentValidation message format. Second reviewer (local stand-in for rate-limited pi) reviewed the post-fix tree: 0 findings; explicitly verified no deadlock cycle across the four locking paths, tenant isolation in raw SQL, and SPA idempotency-key guards. Migration regenerated (branch-only). 178 tests green. Runtime re-verified.
Owner
Author
Review round — applied in 3bb1a0dReviewers: codex + local stand-in for pi (weekly cap, resets ~tomorrow). codex: 0 P1, 12 accepted findings. Stand-in reviewed the post-fix tree: 0 findings.
Stand-in's independent verification of the post-fix tree: no deadlock cycle possible across the four locking paths (item-lockers never wait on lots; lot-lockers only touch the item via FK Migration regenerated (branch-only). 178 tests green. Runtime re-verified: FIFO cost math exact, all guard codes, as-of-date behavior. |
This was referenced Jul 18, 2026
mforce
added a commit
that referenced
this pull request
Jul 18, 2026
…e preservation, help/glossary corrections, a11y (#75) * Fix: depleted flocks reachable for daily-entry backfill Found by the PR #74 accuracy review (post-merge): the Help page, the Flocks screen's own deplete dialog ("backfill for past dates still works"), the glossary, and the domain (Flock.CanRecordProductionOn) all promise backfilled entries for depleted flocks up to their depletion date — but the Daily entry picker filtered to Active-only, so the capability was unreachable in the UI. Picker now includes depleted flocks (archived stay hidden), labeled "— depleted, backfill only", mirroring the feed-usage picker shipped in #70. Default selection still prefers an Active flock; the API continues to gate the exact dates. Browser-verified: depleted flock listed + labeled, default selection Active, and a post-depletion date surfaces the API's lifecycle rejection in the UI. * Apply codex accuracy review of the help page (PR #74, post-merge) codex P1: the help implied medication-withdrawal protection is operational, but no production path sets EggLot.RestrictedUntil — a food-safety overclaim. Stock section, in-app glossary, and GLOSSARY.md now state plainly that nothing marks eggs restricted yet and withholding periods must be managed outside Cluckwork until medication tracking (spec §13) lands. App bug (codex P2): a draft referencing a since-deactivated grade rendered without that line (SPA loaded active grades only) and the next save silently dropped it via ReplaceGrades. Daily entry now loads grades includeInactive; deactivated grades render (labeled) only while a prefilled quantity exists, and the save payload includes them. Doc corrections (codex P2s): deactivated-grade stock does NOT keep selling — existing order lines confirm but new lines are rejected (help + GLOSSARY); "typo in a feed purchase" scoped to quantities only (cost/date/lot number not correctable); usage corrections fix stock, not the create-only usage record or its cost estimate; "drafts freely editable" scoped (flock/date and customer/date are fixed); legacy pre-allocation orders can't self-serve void. GLOSSARY inventory-item entry: all categories support purchases/ corrections, only flock feeding is Feed/Supplement/Additive; deactivation blocks new purchases, not using up stock. UI (codex P2/P3): help tables wrap on phones instead of inheriting the mobile nowrap scroller; glossary terms are th scope=row for screen-reader term-definition association; --muted darkened to clear WCAG AA (4.6:1). Browser-verified: help page sections/anchors/375px clean, depleted-backfill flow intact, rowheader semantics in place. --------- Co-authored-by: mforce <>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #66 (epic #14, Phase 1.1). Part 2 of the split — consumption + the correction path agreed on the issue. Builds on part 1 (PR #68).
What
FeedUsage— create-only feeding record (date, flock, item, quantity, unit snapshot, note) with a lot-cost estimate: Σ(consumed-per-lot × that lot's unit cost) — the §19 feed-cost KPI input. Repo seam rejects Update/Remove; corrections are compensating ledger rows, never edits.POST /inventory/items/{id}/usage— drains lots FIFO under the canonical(ReceivedDate, Id) FOR UPDATElock; one Usage movement per lot drained (lot-level provenance, the F14: Void confirmed sales order — return allocated stock #60 lesson); insufficient stock → 422 with nothing committed. Flock gate reusesCanRecordProductionOn(depleted backfill OK, archived never). Inactive items may still be used up — deactivation only stops new stock.InventoryLot.Adjust— signed correction bounded to[0, QuantityReceived]: below-consumed refuses (InsufficientStock), beyond-received refuses (AdjustExceedsReceived— extra stock is a purchase, not an adjustment).POST /inventory/items/{id}/adjustments—Adjustment(signed) orDiscard(negative only) against a specific locked lot, reason mandatory (whitespace-guarded). A typo'd 5000-instead-of-500 purchase = one negative adjustment; both rows stay in the ledger.GET /inventory/usage— newest first, flock/date filters, paged.Tests (11 new, 173 green)
Adjustbounds both directions,FeedUsageguards.Runtime verified
API scenario (cost 122000 exact, on-hand 80→60 through usage+adjustment, all guard codes) + Playwright UI flow (purchase → usage → correction, headings and ledger updating) — zero console errors.