Appendix: Combined Demand Loss (CDL) v1 — definitions & sources
1. Definitions (per slot t)
| Symbol | Meaning |
| Xn | Number of eMedics available per roster at D−1 23:30 (or 04:00 D0 fallback) |
| Sn | Slots available for booking on D−1. Invariant: Sn = Xn |
| Bn | Number of slots booked out of Sn (captured at D−1 23:00) |
| Xa | Actual number of eMedics available for the slot (polled at T−30 min) |
| Ba | Actual bookings needing service in the slot (polled at T−30 min) |
| Ca | Cancellations = Co (OH) + Cc (customer) |
| Sr | Shrinkage = Xn − Xa |
| CDL | Combined Demand Loss = max(0, Ba − Xa) |
| Sh | Same-home pickups — ignored in v1 |
2. Formulas
| Metric | Formula |
| Sn | Xn |
| Ca | max(0, Bn − Ba) |
| Sr | max(0, Xn − Xa) |
| CDL | max(0, Ba − Xa) |
| CDL % | CDL ÷ Ba × 100 |
| Day rollup | Sum per slot across the 9 morning slots (06:00…10:00) |
3. Data sources & schedule
| What | When (IST) | Source |
| Bn freeze | D−1 23:00 | Scheduler API /api/v1/task/demand — writes demand_snapshots |
| Xn freeze | D−1 23:30 | Scheduler API /api/v1/emedic/shift/list — writes plan_snapshots (is_active && !is_off) |
| Xn fallback | D0 04:00 | Same source — only runs if plan_snapshots empty for D |
| Xa, Ba poll | T−30 per slot: 05:30, 06:00, 06:30, 07:00, 07:30, 08:00, 08:30, 09:00, 09:30 | Scheduler API — writes availability_polls + demand_polls keyed by slot time |
4. Aggregation rules
| Level | How it's computed |
| Slot → Hub day | Each metric summed over the 9 morning slots for that hub |
| Hub → City | Each metric summed over hubs in the city. Never from aggregates — per-slot-per-hub CDL is computed first, then summed |
| Day → Week | Per-day hub totals summed Mon–Sun of the selected week |
| Day → Month | Per-day hub totals summed across the calendar month |
| Ordering | Cities and hubs both sorted by CDL descending (worst first) |
5. Week-off handling
Medics whose shift_calendar row for the date has is_off=true are excluded from Xn entirely. A week-off is captured in this field, so a medic on leave for the day cannot contribute to the plan supply.
6. Projection & data-missing rules (in-progress days)
| Slot state | Xa used | CDL |
| Polled at T−30 | Direct from poll | Real: max(0, Ba − Xa) |
| Poll missing, earlier poll exists | Carried forward (projected) | Projected (italic, amber) against forward-filled Xa |
| Poll missing, no earlier poll | Xa ← Xn (best case) | Plan-ceiling CDL: max(0, Ba − Xn). Floor — real CDL may be higher |
7. Key invariants
- 1 eMedic = 1 pickup per slot. Xn and Xa are head-counts, not multiplied by any slots-per-shift factor.
- Sn = Xn by construction. Customers cannot book more than the roster permits, so Bn ≤ Sn.
- Ba = Bn − Ca at T−30. Ca is observed via the drop, not tagged at source in v1.
- CDL > 0 therefore requires shrinkage (Xa < Xn). If everyone rostered shows, CDL is 0 even if Ba is near capacity.
- Shift-tag (S1/S4) is not a filter. Any rostered medic counts toward morning Xn.