Keep plan warnings in step with the plan they describe

Warnings such as "vacation days at risk of being lost" kept showing after
the planner had already resolved them. The planner itself was firing
correctly -- PlanSyncProvider syncs on every plan-input change -- so the
fault was in the warnings, in two independent places.

The vacation-expiry warning was computed before allocation. It read
`vacation_forfeiting`, which the loader derives from already-committed
usage, while `_assign_tier3` deliberately spends at-risk vacation days
first precisely to avoid that forfeiture. The figure therefore counted
days the plan was in the middle of saving. `_vacation_expiry_warnings`
now subtracts the vacation days this run actually placed for that parent
and year, clamped at zero -- sound because the bank is FIFO, so a day
spent in year Y retires one expiring day one-for-one. The full
carry-forward simulation is still not duplicated inside the ledger.

The Dashboard then never refreshed them. Its proposal came from a
one-shot effect guarded by `proposal === null`, with no planVersion
dependency, so the card kept rendering the pre-replan warning until
remount -- while `syncPlan` was already returning a fresh proposal that
both call sites discarded. PlanSyncProvider now exposes that proposal
behind a monotonic counter, and usePlanProposal prefers it once any sync
has completed, keeping `propose()` for the first load.

Also adds a manual recompute button to Settings, which only bumps
planVersion and reports what the resulting sync did, and fixes partner
add/remove never bumping planVersion at all -- that gap meant gaining or
losing a parent never re-ran the allocator, though it changes who days
can be assigned to. Rename stays cosmetic.

Verified in the browser: a 2031 warning of 15 days dropped to 12 after
three vacation days were planned, without a reload.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014jPFUcCJ5AKXmPVC1anhXe
This commit is contained in:
2026-09-20 14:26:50 +02:00
parent 89aa93e9fd
commit b76fb7417e
14 changed files with 603 additions and 25 deletions
+6
View File
@@ -83,6 +83,12 @@ export const settings = {
'settings.preschoolPlanningDaysLabel': 'Förskolans planeringsdagar per år',
'settings.profileHelp': 'Din lönetyp och sysselsättning används för att uppskatta din SGI och planera din ledighet.',
'settings.profileSectionTitle': 'Din profil',
'settings.recomputeButton': 'Räkna om planen',
'settings.recomputeEvicted': 'Omräkningen skulle ta bort redan inplanerade dagar för att få plats — inget sparades. Justera saldon eller önskemål och försök igen.',
'settings.recomputeHelp': 'Planen räknas normalt om automatiskt när du ändrar något. Använd den här knappen för att räkna om den direkt, utan att vänta.',
'settings.recomputeSuccess': 'Planen räknades om.',
'settings.recomputeTimeout': 'Det tog för lång tid att räkna om planen. Försök igen om en stund.',
'settings.recomputing': 'Räknar om…',
'settings.redDaysHelp': 'En lista över röda dagar enligt den svenska kalendern, tillsammans med dina egna undantag — fyra år i taget.',
'settings.removeBlockerLeaveWishes': 'önskemål om ledighet',
'settings.removeBlockerParentalLeave': 'registrerad föräldrapenning',