P4 — the FULL optimize orchestration now lives in the hub
(POST /roster/optimize-plan): pool (buildUnassigned), day bucketing
(dated-in-window → its day; overdue/undated → day 1 with spillover to
next day if unplaced), vehicles from real shift windows (assignments ×
templates) or assumed 8-16 weekdays (assumed_shift map returned; never
weekends; absences excluded), existing load (occupancyByTechDay) reduces
capacity, origins = home else TARGO depot, priorities from j.priority,
per-job AM/PM windows + duration overrides accepted, OSRM matrix +
OR-Tools solve per day (shared solveVrp, also used by /optimize-routes).
Reusable by the morning auto-plan cron and the field app.
Address rules (user cases baked in, hub-side):
- SAME ADDRESS = ONE STOP: pool jobs sharing an address key (~10m coords
or normalized address) are merged into one solver node (service times
summed) → same tech, single stop. Verified: install + TV boîtier of
the same customer (Cazaville) grouped on Stéphane, 🔗 badges.
- COORDINATION: a pool job at the address of an ALREADY-ASSIGNED job
that day is pinned onto THAT tech (they're going anyway) — verified:
"Réinstallation #253028" pinned to Frédérique who already has the
install there; capable flag kept honest (⚠ if skill missing).
SPA: optimizeSuggestion → hub-first (dates/techs/opts/dur_overrides/
job_windows), entries enriched client-side (lvl/eff/noShift from
assumed_shift); local orchestration kept as emergency fallback. Review
shows 🔗 teal (coordonné avec déjà-assigné) / 🔗 indigo (N jobs même
adresse = 1 arrêt); map merges same-coord stops into one numbered pin.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>