Fix flexible-wish double-booking, extend calendar cache to 2055, add journey tests
Second real bug found by driving the running app while the suites were green. Flexible wishes were funded twice across propose -> apply -> re-propose. Because planned_leave_day carries no wish_id, the engine could not tell that applied days were that wish's own prior occurrence; it treated them as occupied space, routed the candidate search around them, and funded the year again on shifted dates while reporting weeks_funded 1.0. Applying twice turned "one week each spring" into 18 paid days instead of 9. Fixed wishes were unaffected and stay unaffected. Fix (allocation_service.py), per the approved approach of counting already-applied days inside the bounding range rather than adding a wish_id column: - _Ledger._persisted_lookup snapshots existing days BEFORE this run folds in its own freshly-computed windows, so a fixed wish's new placement is never mistaken for a flexible wish's history - _reuse_already_funded_window finds this wish's persisted dates within its bound and reuses the window containing them, via the ordinary fund_window path - full funding therefore yields zero new days and partial funding tops up exactly the remainder, with no duplication and no false shortfall - with no persisted dates, or if the reused window is no longer collision-free, it falls through to the original search, so an unsatisfied year is never frozen Calendar cache extended 2026-2035 -> 2026-2055 (39KB -> 116KB) and the allocator switched to strict, so an uncached year raises UncachedYearError -> ValidationError -> HTTP 422 instead of silently treating Julafton, Nyarsafton and Midsommarafton as working days. Also fixed normalize_day dropping the second name when two holidays share a date (Nationaldagen was being lost). 2049 and 2055 legitimately have 17 red days, not 18: Pingstdagen coincides with Nationaldagen. New backend/tests/integration/test_user_journey.py drives the real app over HTTP across seven journeys: the double-booking guard, the fixed-wish control, apply idempotency, fixed-never-displaced-by-flexible, flexible wishes tracking Easter per year, age-4 arithmetic self-consistency, and a recursive check that no Swedish text reaches the wire now that everything is message_key + data. New backend/scripts/seed_demo.py seeds a realistic workspace through the real service layer for manual testing: demo@example.com / DemoPass123! Backend 414 -> 435 tests. Frontend unchanged at 705. Still not verified in a browser. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RXMhc9nT6sNz1SL4j8dznL
This commit is contained in:
@@ -29,6 +29,24 @@ app/
|
||||
utils/ # errors, logger
|
||||
```
|
||||
|
||||
## Demo data (manual/browser testing)
|
||||
|
||||
`scripts/seed_demo.py` seeds a realistic, ready-to-explore workspace through the
|
||||
normal service/repository layers (no raw SQL) — a couple workspace with a
|
||||
partner, a child born ~6 months ago, vacation rows for only some years (so the
|
||||
`is_assumed` badge is visible), day overrides, and a spread of leave wishes
|
||||
(fixed, flexible, and one deliberately underfunded to show a shortfall +
|
||||
remedies + surplus advice). Login credentials are fixed and printed at the end.
|
||||
|
||||
```bash
|
||||
uv run python scripts/seed_demo.py # create once; re-running is a no-op
|
||||
uv run python scripts/seed_demo.py --reset # wipe the demo workspace and rebuild
|
||||
```
|
||||
|
||||
Then open `http://localhost:5173` and log in with the printed `demo@example.com`
|
||||
credentials. Safe to re-run: without `--reset` it detects the existing demo
|
||||
user and changes nothing; `--reset` only ever deletes the one demo workspace.
|
||||
|
||||
## Reference vertical slice
|
||||
|
||||
`VacationDays` is implemented end-to-end (entity → schema → repo interface →
|
||||
|
||||
Reference in New Issue
Block a user