Files
AdamThomasandClaude Sonnet 5 803db5e9a9 Solveur de suggestions (OR-Tools CP-SAT) — ne place jamais personne
Nouveau module `backend/app/solver/` (mêmes conventions que
`validation/` : models purs, engine pur testé, loader seul lien avec la
base). Pour chaque créneau encore sous son effectif idéal, calcule une
liste ordonnée de bénévoles candidats — c'est la coordination qui
affecte, dans l'écran habituel ; le solveur fait juste remonter ces
candidats en tête de liste (voir le câblage frontend à suivre).

- Seule contrainte dure : aucun chevauchement de créneaux pour un même
  bénévole (règle SHIFT_OVERLAP), à la fois contre l'existant et entre
  deux suggestions du même calcul. L'effectif idéal est un plafond dur.
- Tout le reste est un terme de l'objectif, pas un blocage : priorité
  forte aux créneaux sous l'effectif minimal, bonus vœu de poste, malus
  disponibilité manquante (réutilise `validation.engine.uncovered_minutes`),
  cumul de 8 h et repos (contre les affectations déjà décidées),
  répartition de la charge.
- `POST /editions/{id}/solver/suggestions` (COORDINATION/référent) :
  recalcule à la demande, ne persiste jamais d'affectation.

Dépendance `ortools`. 18 nouveaux tests (moteur + API), 172 tests au
vert, `ruff` et `alembic check` verts. Testé sur le jeu de démo (120
bénévoles, 100 créneaux) : ~0,3 s.

CLAUDE.md : nouvelle section 4 (solveur), renumérotation 5-10,
compétences retirées de « hors périmètre », journal étape 15.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017uUsRg7XzopkCPWimwg9ZM
2026-09-11 08:16:17 +02:00

23 lines
531 B
Python

"""Solveur de suggestions (OR-Tools CP-SAT) — voir `engine.py` pour le détail
des règles. Ne place jamais personne : seule la coordination affecte."""
from app.solver.engine import solve
from app.solver.loader import build_solver_input
from app.solver.models import (
ShiftSuggestion,
SolverInput,
SolverShift,
SolverSolution,
SolverVolunteer,
)
__all__ = [
"ShiftSuggestion",
"SolverInput",
"SolverShift",
"SolverSolution",
"SolverVolunteer",
"build_solver_input",
"solve",
]