# Comptoir

Conseiller conversationnel pour site catalogue. Remplace le moteur à filtres par
une discussion menée par un modèle, et rend au commercial un projet qualifié
plutôt qu'une demande par référence.

## État

Lots 1 à 8 codés. Le moteur n'a jamais appelé l'API réelle : `RepondeurAnthropic`
est écrit d'après la documentation du SDK, pas encore exécuté.

## Tests

    composer install
    vendor/bin/phpunit          # 27 tests, sans base ni clé API
    php tests/apercu.php        # taille et coût du prompt sur un catalogue réel
    php tests/boucle.php        # boucle d'outils complète, hors ligne

## Principe

Le noyau ne connaît ni Laravel, ni HTTP, ni le modèle de données du client, et
n'emploie aucun mot de domaine : ce sont des `items`. Un nouveau site se branche
en implémentant `CatalogueSource` et en écrivant un fichier de configuration.

    CatalogueSource      ← le seul point de contact avec les données du client
      └─ Catalogue       ← index en mémoire, résout et valide les identifiants
           └─ ConstructeurDePrompt  ← consignes + catalogue, mis en cache
                └─ Outils           ← afficher / retenir / transmettre

## Règle d'or

Le modèle ne rédige jamais une donnée du catalogue — ni prix, ni surface, ni
disponibilité. Il désigne des identifiants ; `Catalogue::resoudre()` écarte tout
ce qui n'existe pas, et le site rend la fiche lui-même. Aucune hallucination sur
le stock n'est donc possible, et une fiche retirée disparaît d'elle-même.

## Vérifier sans clé API

    php tests/apercu.php

Construit le catalogue depuis une base locale, affiche la taille du prompt, le
coût par tour, et vérifie que les identifiants inventés sont bien écartés.

Mesuré sur le catalogue réel de Flandre Opale Habitat, 84 items :
préfixe de 18 971 tokens, 0,0095 $ par tour en lecture de cache.

## Configuration

Tout ce qui distingue un client vit dans `config/comptoir.php` : attributs du
catalogue, persona, points que la conversation doit faire aboutir, schéma du
profil capté, plafonds de consommation. Une spécificité qui ne peut pas s'y
exprimer justifie d'étendre la configuration — jamais de brancher une condition
sur le nom du client dans le noyau.
