Part of Phase 1.5 (epic #15). Flagged by codex review of #34 (P1). All date-boundary logic uses IClock.TodayUtc:
- Stock read (
StockEndpoints): withdrawal-restricted vs available classification
- Sale allocation (
ConfirmSaleHandler): the allocationDate passed to the FIFO lock + EggLot.IsRestricted
- Daily-entry future-date validation (
RecordDailyEntryValidator): currently allows +1 day of slack as a stopgap for farms ahead of UTC
For a farm outside UTC this misclassifies around midnight boundaries — e.g. at 18:00 July 15 in America/Los_Angeles, TodayUtc is July 16, so a lot restricted through July 15 reads as available a day early. The spec's restriction rule is farm-local (accounts carry TimeZoneId; spec: "Daily entries lock after 7 farm-local days").
Fix (all together — read and allocation paths must use the same boundary, diverging them is worse than UTC everywhere):
IClock.TodayIn(string timeZoneId) (TimeZoneInfo conversion)
- Resolve the tenant's
Account.TimeZoneId (needs an account lookup port) at the stock endpoint, ConfirmSale, and the entry-date validator
- Drop the +1-day validator slack
Deferred from #34 because the seeded MVP account is UTC and account CRUD doesn't exist yet — the bug is dormant until non-UTC accounts can be created.
Part of Phase 1.5 (epic #15). Flagged by codex review of #34 (P1). All date-boundary logic uses
IClock.TodayUtc:StockEndpoints): withdrawal-restricted vs available classificationConfirmSaleHandler): theallocationDatepassed to the FIFO lock +EggLot.IsRestrictedRecordDailyEntryValidator): currently allows +1 day of slack as a stopgap for farms ahead of UTCFor a farm outside UTC this misclassifies around midnight boundaries — e.g. at 18:00 July 15 in America/Los_Angeles,
TodayUtcis July 16, so a lot restricted through July 15 reads as available a day early. The spec's restriction rule is farm-local (accounts carryTimeZoneId; spec: "Daily entries lock after 7 farm-local days").Fix (all together — read and allocation paths must use the same boundary, diverging them is worse than UTC everywhere):
IClock.TodayIn(string timeZoneId)(TimeZoneInfo conversion)Account.TimeZoneId(needs an account lookup port) at the stock endpoint, ConfirmSale, and the entry-date validatorDeferred from #34 because the seeded MVP account is UTC and account CRUD doesn't exist yet — the bug is dormant until non-UTC accounts can be created.