checkBudget filtrait stats_usage sur `timestamp` (where + fields) et
recevait un 422 à chaque appel : fail-open silencieux, budget jamais
vérifié côté chatbot. Aligné sur le worker : aucune colonne nommée dans
la requête, lecture paginée, mois filtré en JS (timestamp, puis
CreatedAt, puis created_at). Chaque lecture journalise le budget lu ;
un échec journalise « budget NON vérifié » et renvoie verified=false.
Test : scripts/test-circuit-breaker.mjs, faux NocoDB qui rejette en 422
toute colonne absente (15/15 ; 11 échecs si le filtre revient).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0174RrDEQFQTtySXkTcsUKuv
Le second choix du double type se lit en contour (texte --nav-text), le
principal passe en fond plein --nav-primary-solid : 4,16:1 → 14,6:1 mesuré
(le fond actif translucide de Chip.vue était sous AA). Survol collant
neutralisé sur tactile, annonce sr-only « Principal · second choix ».
Scopé à FormLibre ; Chip.vue non modifié (défaut global signalé).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AzGo8bxhHp6M9RxuAFbyLU
RAPIDE groq/llama-3.1-8b-instant → groq/openai/gpt-oss-20b ; APPROFONDI
groq/llama-3.3-70b-versatile → groq/openai/gpt-oss-120b ; replis inchangés.
Les chatbots vivaient sur le repli Gemini depuis le retrait.
gpt-oss raisonne : ses tokens de raisonnement sont décomptés de max_tokens.
REASONING_MARGIN_TOKENS (800) ajouté au budget des trois routes, et
bifrostContent() signale au journal une réponse tronquée (finish_reason
length). Le champ message.reasoning est ignoré. Défaut WORKER_MODEL aligné
sur la prod. En-têtes « Mistral Small » corrigés, PIPE-IA-DOC §11.3.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AzGo8bxhHp6M9RxuAFbyLU
Doublon hérité du mapping heuristique v4.1 : retiré chez hal-harvey
(ingere: false, poster Bon Pote non ingéré), conservé chez david-harvey
avec bio et thèses réelles. Écoles inchangées. auteurs_ingeres_count
recompté sur les flags (91, la valeur 80 était obsolète).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UvxdoEGWjCTSEJDmraYW96
Deux chips maximum : le premier alimente submission_type, le second
s'écrit en tête de description_user (« Type suggéré : X ou Y »), sans
ALTER NocoDB. Le marqueur « Type : non précisé » n'est posé que sans
aucun type (contrat worker/enrich.js inchangé). ?categorie= présélectionne
un seul chip. Tests : 16/16.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UvxdoEGWjCTSEJDmraYW96
Checkpoint Fable 27/09 : sans lien, nomSuggere() reprenait 60 caractères du texte du contributeur et les envoyait sur un topic ntfy (public par URL). Le nom n'est transmis que s'il vient d'un hostname. Click → sheets.trans-former.fr (localhost inutilisable depuis un téléphone). trackingUrl pointait nav.trans-former.fr/suivi/, page inexistante.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Reprend worker/enrich.js (fusion, pas réécriture) pour le nouveau format de
soumission libre et l'infra en prod (décisions MOE du 27/09) :
- LLM Mistral direct → Bifrost (${BIFROST_URL}/v1/chat/completions,
x-bf-vk), modèle WORKER_MODEL (défaut groq/llama-3.1-8b-instant).
- Scrape crawl4ai/Python → fetch natif Node 22 : timeout 8s, corps
plafonné 500 Ko, titre + meta description + og:* + texte tronqué 4000c.
- Email Resend → notification ntfy, jamais l'email ni le texte du
contributeur (id NocoDB, nom suggéré, type, confiance uniquement).
- Sortie LLM {nom, description, type_suggere, ville, tags, confiance} ;
le worker ne réécrit `nom`/`submission_type` que si le formulaire assoupli
a laissé un placeholder ("[à qualifier]" / "Type : non précisé").
- Seuil « 5 fiches pending » retiré (décision volume faible, notée si le
volume remonte).
- --dry-run : fixture locale, mock Bifrost/scrape par défaut, aucune
écriture NocoDB, DRY_RUN_LIVE=1 pour forcer de vrais appels réseau.
- worker/daily-digest.js supprimé (non référencé, cron purgé le 15/07).
deploy/aep-worker/ : service + timer (15 min) + README avec les étapes
exactes de déploiement pour la session qui déploiera (backup NocoDB,
copie, systemctl, test bout-en-bout M3) — rien exécuté ni copié ici.
PIPE-IA-DOC.md §11 : documente tous les écarts vs la version NAV V2 d'origine.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Le contributeur colle un lien (ou plusieurs) et explique en texte libre
pourquoi c'est pertinent, sans template ni minimum de caractères. Le type
devient une suggestion optionnelle (chips). Les 5 formulaires typés restent
disponibles derrière « Mode détaillé » (replié par défaut).
- utils/submitLibre.ts : schéma Zod partagé client/serveur + mapping vers les
colonnes NocoDB existantes (aucun changement de schéma) — table orgas par
défaut, table ressources_references si le chip « Références » est choisi.
- components/FormLibre.vue : liens dynamiques (1-10), texte libre, chips,
email optionnel, honeypot.
- server/api/submit/index.post.ts : branche mode=libre en amont du schéma
typé existant ; email Jules remplacé par ntfy (server/utils/notify.ts) —
jamais l'email ni le texte du contributeur dans la notif.
- scripts/test-submit-libre.mjs : 6 cas contre le vrai schéma Zod (via jiti).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Décisions Jules du 27/09 : ① À propos sans les cartes Mistral Nemo / Small
(modèles qui ne sont plus en service), Le Chat sans « souverain » (outils.vue
et fmhy-curated.json) ; ② le bandeau bas (transparence IA + don) est retiré,
le menu déroulant devient visible à toutes les largeurs et porte un bouton
Soutenir → liberapay.com/trans-former.fr/donate (onglets masqués dedans ≥1024px).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Arbitrages de Jules du 26/09 (table R §6) : 2A Jobs en S (tête ← slide 16),
1A Réseaux AEP en M (tête ← slide 17), 6 retrait de « Propulsé par Mistral »
et du badge « IA souveraine : Mistral AI », sans rien affirmer à la place.
- pages/trouver-du-taf.vue : EchelleTete S sous le titre, centrée comme l'en-tête ;
note du chatbot réduite à « 20 questions/jour ».
- pages/agences.vue : popup Réseaux avec echelle="M".
- ChatbotPlaceholder, ChatbotSheet : phrase « serveur européen souverain
(Mistral FR, zéro rétention) » retirée.
- a-propos : badge « IA souveraine » retiré.
Non touchés : cartes ia-card « Mistral Nemo / Small » d'À propos, « Mistral Le Chat »
d'Outils (hors consigne).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- utils/echelles.ts : texte des slides 15 à 18, mot pour mot, source unique
(la future nav S / M / XL lira ce fichier).
- EchelleTete.vue : badge d'échelle, titre, sept mots, phrase, ligne
« Chaque section est ouverte aux contributions » vers /proposer.
- Placée en tête du texte existant, sans le remplacer : Outils (S),
popup Écosystème Entraide (M), page Codev (M), popup média (XL).
Réseaux AEP et Jobs attendent les arbitrages n° 1 et 2 (table R §6).
- /proposer?categorie=<id> présélectionne l'onglet.
- Menu mobile : « recherche-média » pointait sur /rag (301), pointe sur /media,
état actif comme les autres liens.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- components/Chip.vue (nouveau) : label/variant(echelle|fonction|posture)/
active/count/as(button|span)/removable, emits toggle+remove, aria-pressed
natif sur as=button, croix "Retirer {label}" accessible. Styles 100% tokens
DS (--primary/--on-primary/--bg-alt/--accent/--on-accent/--focus-ring/
--dur-fast), hover translateY, focus-visible outline var(--focus-ring),
transition coupée sous prefers-reduced-motion. Taille compacte 32px de haut
mesurée (tap ok).
- components/ChipGroup.vue (nouveau) : role="group" + aria-label + flex-wrap
gap — garantit le wrap propre exigé (jamais une ligne à virgules).
- EchelleFilter.vue, FonctionFilter.vue : rendu remplacé par Chip/ChipGroup,
props modelValue/counts et événement update:modelValue strictement
inchangés (NavSidebar.vue n'a rien à changer côté logique). FonctionFilter
passe le rang de sélection (comme avant) via le prop count de Chip.
- HashtagFilter.vue : seule la liste HASHTAGS (togglable, grammaire fonction)
passe en Chip/ChipGroup. Les chips FAMILLES gardent leur rendu et leurs
couleurs propres par famille (hors grammaire échelle/fonction/posture,
hors périmètre B3 — les changer aurait été une refonte, pas un branchement).
- pages/agences.vue : hashtags par structure (liste sidebar) en
Chip as="span" variant="fonction" (non cliquables avant, le restent).
- pages/index.vue : la sheet mobile ne passe PAS par NavSidebar/EchelleFilter/
FonctionFilter — elle a son propre bloc de chips dupliqué (découvert en
testant le mobile, absent du périmètre écrit du brief). Direction du parti
design ("chips codées par dimension", mobile-first explicite) : convertie
en Chip/ChipGroup elle aussi, mêmes handlers toggleEchelle/toggleFonction
inchangés. Effet de bord positif : le nombre par fonction (déjà calculé,
jamais affiché sur mobile) apparaît désormais aussi en mobile, à parité
avec le desktop.
- components/TagBadge.vue supprimé : son seul consommateur, OrgCard.vue,
n'est importé nulle part dans l'app (grep vérifié) — code mort. OrgCard.vue
supprimé avec lui plutôt que laissé avec une référence à un composant
disparu.
- components/TypeBadge.vue : conservé tel quel — ce n'est pas un filtre, et
sa grammaire couleur par type (7 couleurs Tailwind fixes) est orthogonale
à échelle/fonction/posture ; le convertir en Chip aurait perdu l'info de
type ou inventé une 4e variante non validée.
Vérifié : npm run build OK. Chips wrap avec gap en clair/sombre/mobile
(390px, hauteur mesurée 32px). Dark mode : contraste texte/fond conforme
(safran = texte sombre, jamais blanc).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- package.json : dépendance @transformer/ui (git+https design-system.git)
- nuxt.config.ts : css tokens.css + theme/aep.css chargés avant main.css
- assets/css/main.css : --nav-bg/-bg-alt/-surface/-primary/-accent/-text/
-text-muted/-font deviennent des alias var(--role) DS ; focus ring sur
var(--focus-ring). --nav-primary-raw, --nav-primary-solid, --nav-accent-soft
et --nav-text-on-primary restent des valeurs propres à nav-carte (pas
d'équivalent DS fiable en sombre — --nav-text-on-primary sert de contraste
à la fois sur --nav-primary translucide et --nav-primary-solid opaque, deux
fonds dont la légèreté s'inverse en sombre ; aliaser sur --on-primary DS
cassait le contraste du logo AEP et de ~10 boutons en sombre, testé au
pixel et reverti)
- tailwind.config.js : couleurs nav.* pointent vers les variables --nav-*
(pas de darkMode:'class' ajouté — aucune classe dark: Tailwind en usage)
Vérifié : npm run build OK, diff pixel avant/après < 0.5% sur home + agences
en clair/sombre (bruit = badge Nuxt Devtools, pas les tokens).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
CARTO Basemaps exige une clé depuis le 23/09/2026 : sans elle, chaque tuile
porte le filigrane « API KEY REQUIRED ». Clé lue au runtime
(NUXT_PUBLIC_CARTO_KEY) ; sans clé, repli sur le Plan IGN (Géoplateforme).
FicheDetail quitte aussi les tuiles OSM (418, politique d'usage).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Catalogue lu au runtime par le chatbot par-auteur (171 auteurs, 10 ecoles,
corpus 277). Jamais versionne -> droppe des builds -> feature cassee en prod.
Desormais tracke + converti UTF-16->UTF-8 (le serveur lit en utf-8).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01M4VP2GCZfGY2zWs9NAC84X
- fix: layout-toggle-bar à l'intérieur du layout-container (entre carte D3 et chatbot)
- fix: chatbot de nouveau visible en mode split
- feat: nav "Écosystème Entraide Architecture" → "Écosystème Entraide"
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- fix: server route /data/auteurs-pensees.json (contournement bug manifest Nitro)
- fix: contentView indépendant du layoutMode — boutons CARTE PRINCIPALE / bonpote / RAG backend ne modifient pas l'état carte-full/chatbot-full
- feat: bouton CARTE PRINCIPALE → restaure la vue D3 + chatbot split
- fix: /rag redirige vers /media (301)
- feat: nav "RAG en construction" → "recherche-média" lien /media
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Hamburger:
- Ajout Jobs, Manifeste, Soutenir
- Ré-ordonnancement (cartes/RAG/Codev en haut, ressources en bas)
Pop-ups Mission:
- MissionPopup générique (slot, props title/ctaLabel/storageKey)
- Auto-show 1ère visite Carte 1 (Entraide) et Carte 2 (Réseaux AEP)
- Bouton (i) flottant pour rouvrir
Pages:
- /manifeste : nouvelle page (texte version page-carto-V1)
- /a-propos : section 1 retirée (devient pop-up Carte 1) + scroll latéral fixé
- /agences : 3e onglet "Graphe" sur mobile + labels structures sur GraphView
- /trouver-du-taf : intro pédagogique repliable (onglets / tags / 5 axes),
filtres mobile repliables, "Plateformes B2C" → "Pour archi indépendants"
Mobile UX:
- FAB coeur jaune Soutenir retiré (BandeauBas) — accessible via hamburger
- FicheModal/V2 : décalage top:76px sur mobile pour ne plus mordre header
- Logo header : "Architecture d'Écologie / Politique" en clair (2 lignes)
Cause racine résolue:
- /api/chatbot-reseaux n'avait jamais été déployé → 404 en prod avant ce build
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Route /agences → /api/chatbot-reseaux garanti, même si prop non reçu.
Titre du chatbot affiche la carte active pour confirmation visuelle.
activeEndpoint computed depuis props.endpoint ?? route-based detection.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- CSS: :deep(.md-content) perce le scoped — résout l'écrasement par .assistant-bubble p
- Template: <template v-if> / <template v-else> au lieu de <p v-if /> + v-else
(tag void + v-else = pairing HTML instable)
- Carte 1 retrouve son onboarding d'origine (v-else sur props.onboarding absent)
- Carte 2 garde son onboarding 120 structures via prop
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- ChatbotSheet: import explicite useMarkdown (plus d'auto-import incertain)
- Props: title, onboarding, endpoint
- agences.vue: titre 'Réseaux AEP' + message d'accueil distinct + endpoint correct
- Header chatbot affiche le nom de la carte active
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- server/api/chatbot-reseaux.post.ts : keyword search sur reseaux-bifurcation.json
(120 structures, même pattern que chatbot-taff)
- ChatbotSheet.vue : prop endpoint? (défaut /api/chatbot) + renderMd déjà actif
- agences.vue : endpoint='/api/chatbot-reseaux'
Markdown s'active au prochain restart du bat (cache .nuxt à nettoyer).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Import direct du JSON au moment du build (bundlé par Rollup).
Supprime serverAssets et useStorage qui ne marchaient pas en dev Nitro.
Ajoute GET /api/plateformes-taff comme endpoint réutilisable.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- nuxt.config.ts: nitro.serverAssets pointe sur public/data/
- chatbot-taff: useStorage remplace readFileSync et $fetch
(fonctionne dev + prod sans dépendance filesystem ni réseau)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Remplace readFileSync (chemin instable Nitro) par $fetch sur le serveur
lui-même qui sert déjà plateformes-taff.json en statique.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>