# Bifrost — routage texte par coût : état de la mesure (18/07/2026) ## Découverte clé : la mesure existe déjà Bifrost journalise TOUT dans `/volume1/docker/bifrost/data/logs.db` (SQLite, table `logs`) : `virtual_key_name`, `model`, `prompt_tokens`, `completion_tokens`, `cost` ($ réels), `latency` (ms), `status`, `error_details`, `fallback_index`, `number_of_retries`. Aucune instrumentation à développer. Lecture en RO : ``` sqlite3 'file:/volume1/docker/bifrost/data/logs.db?mode=ro' ``` Depuis mcp-nas : chemin `/mnt/docker/bifrost/data/logs.db`, via `python3 -c` (sqlite3 CLI absent). ## Requête de référence — coût 30 j par clé × modèle ```sql SELECT COALESCE(virtual_key_name,'(aucune)'), model, COUNT(*), SUM(prompt_tokens), SUM(completion_tokens), ROUND(SUM(cost),4), SUM(CASE WHEN status!='success' THEN 1 ELSE 0 END) FROM logs WHERE timestamp >= datetime('now','-30 days') GROUP BY 1,2 ORDER BY 6 DESC; ``` Coût par tâche aboutie : `AVG(cost) WHERE status='success' AND cost>0`, par modèle. ## Constats (30 j au 18/07/2026) - Dépense totale ≈ **1,47 $/30 j** (~15 % du plafond OpenCode 10 $). Pas d'urgence budgétaire. - deepseek-v4-flash : 774 succès, **1,38 m$/tâche**, 1 942 tok sortie moy, 22,6 s. - kimi-k2.6 : 93 succès, **3,99 m$/tâche** (2,9× flash) pour 909 tok sortie — confirme que le prix affiché au token ne prédit pas le coût par tâche. - 22× HTTP 429 `GoUsageLimitError` sur flash : le plafond OpenCode se fait déjà toucher. - 270 replis `fallback_index=1` sur flash ; `attempt_trail` vide → destination du repli non tracée. ## BLOQUANT attribution : une seule clé pour tout Seules 2 clés virtuelles actives (`Nabil-Key`, `Yesmine-Key`). Tous les consommateurs (hermes ×3, crons veille, n8n, apps) partagent Nabil-Key → coût par consommateur IMPOSSIBLE. `metadata` vide, `raw_request` vide. Prérequis n°1 avant tout routage : **une clé virtuelle Bifrost par consommateur** (hermes-tt / hermes-nyora / hermes-perso / n8n / veille-infra / veille-nexum / redaction-pro / family-help / nyora-veille / gsparc-mezzouna / reglement-definitif). Zéro code — config governance Bifrost + .env clients. ## Incident en cours : 879× 401 en 30 j `virtual_key_not_found` (784) + `virtual_key_required` (95), encore 4–26/jour cette semaine, pic 328 le 11/07. Le client demande `deepseek-v4-flash` avec une clé absente de la DB — probablement l'ancienne clé `yesmine-hermes-desktop` (vue dans les logs, absente de config.db) ou une clé rotée. Un service croit appeler le LLM et échoue en silence depuis des semaines. Identification : `docker logs bifrost` → IP source 172.27.x.x → container (réseau n8n). ## Protocole de mesure retenu (AVANT toute ligne de routage) 1. Créer les clés virtuelles par consommateur, distribuer dans les .env, redémarrer les clients. 2. Trouver et corriger l'émetteur des 401. 3. 7 jours de collecte attribuée, puis tableau coût/mois par consommateur (requête ci-dessus). 4. Définir les besoins texte à partir des données mesurées (piste : exécution-outils / rédaction / raisonnement-agentique / vision-OCR / extraction structurée). 5. Seulement ensuite : sélecteur type nyora_models.py côté Bifrost, avec repli journalisé. ## Pièges - `attempt_trail` est vide dans cette version de Bifrost : la cible réelle d'un repli ne se lit pas dans logs.db — journaliser côté sélecteur. - Comparer m$/tâche entre modèles n'a de sens qu'À BESOIN ÉGAL (mimo-v2.5 affiche 0,53 m$/tâche mais sur des tâches à 84 tok de sortie — biais de sélection). - config.db : clés provider en `plain_text` — ne jamais SELECT les colonnes `value` en clair. Gabarit du sélecteur : VPS hermes-nabil `/data/nyora/nyora_models.py` + section 7 de `common/hermes-nabil-images-flyers-navigateur.md`. --- ## DÉPLOIEMENT FAIT (18/07/2026, session vacances) **13 clés virtuelles créées et actives** : vk-hermes-tt/nyora/perso, vk-n8n, vk-veille-infra, vk-veille-nexum, vk-redaction-pro, vk-family-help, vk-nyora-veille, vk-gsparc-mezzouna, vk-reglement-definitif, vk-nyora-doc-api, vk-nyora-notes (les 2 derniers = consommateurs découverts dans les logs, absents de l'inventaire initial). Valeurs dans `/volume1/docker/hermes-platform/.env` (`BIFROST_VK_*`). Providers clonés de Nabil-Key. **Pilote actif : redaction-pro** route sur `vk-redaction-pro` (nginx.conf, backup `.bak_vk_20260718`). Premier consommateur attribuable dans logs.db. Comparer coût/qualité à J+7. ### Pièges rencontrés - **L'API governance IGNORE `allow_all_keys` en POST ET en PUT** (stocké 0) → fix obligatoire : `UPDATE governance_virtual_key_provider_configs SET allow_all_keys=1 WHERE virtual_key_id IN (SELECT id FROM governance_virtual_keys WHERE name LIKE 'vk-%')` **+ restart bifrost** (config governance cachée en mémoire, l'UPDATE seul ne suffit pas). Sans ça : 400 "no keys found for provider". - **mcp-nas ne peut pas écrire les fichiers root de /mnt/docker** → édition via container éphémère : `docker run --rm -v /volume1/docker:/w alpine sh -c '...'` (clé lue depuis .env dans le container, jamais affichée). - **SSH mcp-nas → NAS** : la clé existe dans /root/.ssh/mcp-nas-bestof avec alias **`ssh nas-host`** (config déjà en place — ne pas conclure trop vite à la clé perdue). - bifrost-proxy log des [emerg] "host not found in upstream" à chaque boot NAS (course avec bifrost) mais **s'auto-répare** via restart:always ~20 min après. Pas d'action requise, ne pas paniquer sur ces logs. - `/volume1/docker/hermes-platform/.env` est en **777** (piège chmod documenté) — à corriger avec précaution (vérifier qui lit le fichier et sous quel uid) au retour. ### 401 : état après enquête Émetteurs (96 h) : redaction-pro (31 — clé pourtant VALIDE : autre chemin de code à trouver, l'attribution par clé rendra le coupable visible), nyora-doc-api (12), nyora-notes (8), veille-backend (3), n8n (2). Pas une clé morte unique : plusieurs chemins de code défaillants. La bascule par consommateur est le bon outil de diagnostic. ### SÉCURITÉ — rotations requises (exposition en clair le 18/07) 1. **Clé provider OpenCode** (BIFROST_OPENCODE_KEY) — affichée dans un traceback. 2. **Token Cloudflare Workers AI** (redaction-pro nginx.conf, location /api/cf/) — affiché malgré masquage partiel. Rotation des deux au retour + mise à jour .env/nginx.conf. ### Reste à faire (retour de vacances) - Basculer hermes ×3 (localiser où chaque agent stocke sa clé Bearer), n8n (credential), gsparc, family-help, nyora-veille, veille-infra/nexum, doc-api, notes → chacun sa clé. - Élucider le chemin 401 de redaction-pro (la moitié de son trafic échoue). - J+7 : tableau coût/consommateur (requête de référence ci-dessus) puis définition des besoins.