La rupture calculee (autoUnavailableIds) etait deja derivee mais pas
appliquee au parcours de commande. Desormais :
- CatalogueController expose is_orderable par produit/menu (menu = burger
impose seul), en croisant le catalogue avec autoUnavailableIds en une
requete (pas de N+1). La borne (data.js -> commandable) grise la tuile +
badge "Indisponible" et bloque le clic (page-products.js + CSS).
- Garde SERVEUR a la creation de commande (OrderRepository::resolveLine) :
un produit, ou le burger d'un menu, en rupture est refuse quel que soit
le canal, y compris par acces direct ou repli sans-JS. C'est la couche
qui fait foi ; le grisage borne n'est qu'un echo UX.
Tests : CatalogueControllerTest (is_orderable liste+detail, produits+menus),
OrderRepositoryTest (refus a la commande produit + menu burger), data.test
(commandable). Doubles desambiguises (autoUnavailableIds vs composition).
PHPStan L6 propre.