# Dubbeldagar: combined pot, and a corrected premise > **Verdict** > 1. **Combined, yes.** The 60-day dubbeldagar cap is one pot per child, shared by both > parents — the code gets this right. > 2. **Not a separate pot — this is the premise to correct.** A dubbeldag is not a bonus day on > top of the 480. On a doubled date, **each parent spends one of their own parental-benefit > (FP) days**. The 60 caps how many *dates* may be doubled, not an extra allowance. Excluding > dubbeldagar from "the total pot of days" would overstate how many days the family actually > has — it would double-count nothing, because there's nothing extra to exclude. > 3. A per-parent `dubbeldagar_left` value is scraped from Försäkringskassan and stored, but the > allocator never reads it — see §3 below. Flagged, not fixed. This answers the question in `todo.md`: *"Is it clear that dubbeldagar is something that two parents have combined ... not that parent A has e.g. 60 days and parent B has 60 additional days? ... And these days shouldn't be included in the total pot of days to use for parental leave."* --- ## 1. Combined: one pot per child The cap is tracked per **child**, not per parent. In `backend/app/services/allocation_service.py:739`: ```python self._dubbeldagar_used: dict[UUID, int] = {} ``` keyed by `child.id`. It's checked against `_MAX_DUBBELDAGAR = settings.rules.max_dubbeldagar` (default 60, `backend/app/config.py:34`), and only within `settings.rules.dubbeldagar_months_limit` = 15 months from the child's birth date (`config.py:35`). Both checks happen together in `_fund_both` (`allocation_service.py:1225-1234`): ```python eligible_end = child.birth_date + relativedelta(months=_DUBBELDAGAR_MONTHS_LIMIT) used = self._dubbeldagar_used.get(child.id, 0) dubbeldagar_legally_available = ( pool_a is not None and pool_b is not None and any(d <= eligible_end for d in dates) and used < _MAX_DUBBELDAGAR ... ) ``` and the running count is written back once per window at `allocation_service.py:1334`: `self._dubbeldagar_used[child.id] = used`. There is exactly one counter per child; neither parent has their own 60. This is independently re-checked at *apply* time (when a plan is actually saved, not just proposed) by `AnalyticsService.validate_dubbeldagar` (`backend/app/services/analytics_service.py:221-254`), via `PlannedLeaveRepository.count_dubbeldagar(child_id)` — again scoped to the child, not a parent, and again compared against `settings.rules.max_dubbeldagar`. So: yes, it's clear in the code, and correct. One combined 60-day pot per child. --- ## 2. Not a separate pot — correcting the premise The `todo.md` framing — "these days shouldn't be included in the total pot of days to use for parental leave" — treats a dubbeldag as if it were a bonus day, separate from the 480 (390 sjukpenning + 90 lägstanivå) each parent has. **That isn't how the engine models it, and it isn't how the Swedish rule works:** a dubbeldag is a *convenience*, not an *allowance*. Look at the actual funding branch, `_fund_both` (`allocation_service.py:1263-1289`). On a date that's funded as a dubbeldag, **both** parents get an ordinary `ProposedDay` charged against their **own** FP pool: ```python self._commit_fp_tier(pool_a, tier_a) self._commit_fp_tier(pool_b, tier_b) used += 1 cost[tier_a] += 1 cost[tier_b] += 1 days.append(ProposedDay(d, parent_a.uuid, child.id, tier_a, True, wish.id, REASON_DUBBELDAG)) days.append(ProposedDay(d, parent_b.uuid, child.id, tier_b, True, wish.id, REASON_DUBBELDAG)) ``` `self._commit_fp_tier(pool_a, tier_a)` decrements parent A's own `sjukpenning`/`lagsta` pool by one; the identical call for `pool_b` decrements parent B's own pool by one, for the *same calendar date*. Two FP days are spent — one from each parent's existing 480 — not one shared day pulled from somewhere else. `PlannedLeaveDay.is_dubbeldag` (`backend/app/entities/planned_leave.py:16`) just tags that row as counting toward the 60-date quota; it doesn't change which pool it draws from. So the 60 is **a cap on how many dates may be doubled**, not extra days on top of the 480+480 the two parents already have. Both parents being off on the same date normally costs the family one FP day and one vacation day (co-leave, see §4). A dubbeldag instead costs two FP days — it lets you trade a vacation day for an extra FP day, for up to 60 dates, early in the child's life. It is not free time; it's a different way to spend time you already had a claim to. **Practical consequence:** excluding dubbeldagar from "the total pot of days" would be wrong, because there is no separate pot to exclude — every dubbeldagar-tagged day is already counted inside the ordinary sjukpenning/lägstanivå totals it was drawn from. Subtracting it again would understate the family's real entitlement, not correct for a double-count that doesn't exist. --- ## 3. A loose end: a per-parent `dubbeldagar_left` that nothing consults There's a field that *looks* like it might contradict §1 — `ParentalLeaveFetch.dubbeldagar_left` (`backend/app/entities/parental_leave.py:41`, column at `backend/migrations/versions/001_initial_schema.py:132`). It's scraped from Försäkringskassan per (parent, child) (`backend/app/scrapers/fk_scraper.py:640-663`) and validated on ingest by `backend/app/services/leave_snapshot.py:146-158` (non-negative, ≤ `rules.max_dubbeldagar`). It's carried into the allocator's input as `DayPool.dubbeldagar_left` (`allocation_service.py:2457-2460`, sourced from `latest.dubbeldagar_left` at line 2430, or defaulted to `rules.max_dubbeldagar` when there's no FK snapshot yet, line 2438), and again into the mutable `_MutablePool.dubbeldagar_left` (`allocation_service.py:649, 732`). Grepping every place that field is actually *read* (`\.dubbeldagar_left` as an attribute access, not a constructor argument) turns up exactly four sites, and all four are construction/copy sites — `_MutablePool` build-out (line 732), the candidate-probe scratch copy (line 1688), the `DayPool` build-out (line 2209), and the initial assignment from the FK snapshot (line 2430). **None of the decision logic in `_fund_both` — the eligibility check at lines 1225-1234, or the spend at lines 1263-1289 — ever reads `pool.dubbeldagar_left`.** It relies exclusively on `self._dubbeldagar_used[child.id]` and `_MAX_DUBBELDAGAR`, described in §1. The scraped per-parent number is loaded, validated, and passed all the way through the pipeline, and then never consulted. `ARCHITECTURE.md:491` still shows illustrative pseudocode from an earlier design that *does* consult it (`if latest_fetch.dubbeldagar_left - await self._planned_dubbeldagar(child_id) <= 0`) — that shape was superseded by the combined per-child counter this doc describes, and the architecture doc wasn't updated to match. This also makes the field conceptually wrong given §1: FK reports it per parent, but the real constraint is per child, shared. Two parents' FK snapshots could show two different `dubbeldagar_left` numbers for the same child, and neither would be authoritative — the allocator's own `_dubbeldagar_used` counter is. Flagging this; not changing it (no code changes in this pass). TODO: decide whether to (a) stop scraping/storing per-parent `dubbeldagar_left` and derive `max_dubbeldagar - count_dubbeldagar(child_id)` everywhere instead, or (b) keep it only as a display/cross-check value and make that explicit in the UI. Not decided here — a wrong number is worse than no number, per `CLAUDE.md`. --- ## 4. Dubbeldagar vs. the default co-leave behaviour Since the 2026-09-18 correction (`PLANNING_ENGINE_SPEC.md` §3.5, "co-leave"), a `parent_mode == 'both'` window does **not** default to dubbeldagar. It defaults to **co-leave**: one parent funded on FP, the other on vacation, same date (`strategy = 'co_leave'`, `allocation_service.py:1291-1329`). Dubbeldagar (`strategy = 'dubbeldag'`) only fire when the wish's `wants_dubbeldag` flag is explicitly set (`allocation_service.py:1235, 1263`) **and** the date is legally eligible (§1). The practical difference, for a single date both parents are home: | Strategy | Parent A spends | Parent B spends | Net cost | |---|---|---|---| | Co-leave (default) | 1 FP day | 1 vacation day | 1 FP + 1 vacation | | Dubbeldagar (opt-in) | 1 FP day | 1 FP day | 2 FP, 0 vacation | Dubbeldagar trade a vacation day for an extra FP day — worth doing only while the 15-month/60-date window is open and only if FP days are more plentiful than vacation for that family. Co-leave is the safe default that works for every date, indefinitely, with no quota to track.