Lot 3 — Veille agentique : spécification
Spécification du pipeline de veille automatisée : suivre l'actualité (IA, dev web, qualité, juridique), résumer, classer et alimenter
pilotage/veille/— sous contrôle humain. Rattaché au cadre :specs/ia-vitrine.md. Statut : V1 complète bout-en-bout côtételaria(commits0e26ea0..e776aca, 25 tests PHPUnit verts). Pipeline planifié actif (Scheduler+Messenger câblés, cadence 15 min) + dashboard/admin/veille+ revue propositions (bb77c65). Catalogue des flux V1 et réserve V2+ :ia-veille-sources.md.
1. Objectif et périmètre
C'est la surface « agentic automation » de la vitrine : démontrer une automatisation IA planifiée, utile et encadrée. Le pipeline collecte des sources, les résume, les classe et propose des entrées dans la veille existante.
- Symfony-natif (Scheduler + Messenger), pas de SaaS no-code (cohérent avec le cadre).
- Génération via Claude ; déduplication et rapprochement thématique peuvent réutiliser les embeddings du cœur (L0).
- Ce n'est pas un produit : sortie = propositions révisées par un humain.
Périmètre V1 : un thème pilote (IA), bout-en-bout (collecte → résumé → classification → proposition d'écriture). Hors V1 : tous les thèmes, tableau de bord, publication automatique, alerting.
2. Flux
Sources (RSS/Atom, gérées en base via /admin/veille/sources)
│ (planifié : Scheduler — câblage reporté)
â–Ľ
Collecte ──▶ Déduplication ──▶ Fetch article ──▶ Résumé (Claude Haiku) ──▶ Classification ──▶ Écriture proposition
(Messenger) (URL ou hash) (DOM lazy) (+ source/lien) (mots-clés V1) var/veille/proposals/*.md
│
Revue humaine ──▶ bascule vers pilotage/veille/
Le fetch article est nécessaire en pratique car la quasi-totalité des RSS ne fournissent que titre + lien (HN, HuggingFace, blogs Markdown) — sans contenu, le résumeur Claude refuse de halluciner.
3. Composants (Symfony-natif, domaine in-app src/Veille/)
Le domaine veille vit dans l'application telaria (src/Veille/), pas dans un bundle. C'est une surface app, pas un socle réutilisable. Extraction (telaria/veille-bundle) si un autre projet en a besoin un jour — pas avant.
3.1 Sources (entité Doctrine VeilleSource)
- Flux RSS/Atom uniquement en V1 (couvrent 95 % du besoin pour un pipeline Symfony en pull). Pas de JSON Feed, pas de webhook, pas de scraping de pages sans flux.
- Thèmes visés : IA, dev web, qualité, juridique (CNIL, AI Act / EUR-Lex).
- V1 = thème IA uniquement, 10 flux sélectionnés (4 constructeurs majeurs, 1 souveraineté FR, 1 recherche source arXiv, 2 synthèses anglo, 1 source FR pro, 1 pulse Hacker News filtré).
- Stockage : entité Doctrine
VeilleSource(pas de config-as-code, pas de doc-as-code). Justification : maintenance opérationnelle continue (ajout/retrait d'un flux sans redéploiement), séparation des responsabilités IA (consommateur) / humain (éditeur). - Administration : CRUD
/admin/veille/sourcescôté telaria. - Champ
typeobligatoire :native(RSS officiel exposé par l'éditeur),community(flux maintenu par un tiers via GitHub Actions),html(réservé V2). Plusieurs labos IA majeurs (Anthropic, OpenAI, Mistral, Meta, xAI) n'exposent plus de RSS natif depuis leurs refontes récentes — on dépend de flux communautaires (Olshansk/rss-feeds,0xSMW/rss-feeds), à monitorer. - Charge estimée V1 : ~30-50 items/jour après dédup.
- Liste exacte des URL, justifications et catalogue de réserve :
ia-veille-sources.md.
3.2 Collecte planifiée
- Symfony Scheduler :
Schedule "veille"à cadence globale 15 min en V1 (champVeilleSource.scheduleISO 8601 reste informatif — la cadence per-source sera prise en compte en V2). - Symfony Messenger : traitement asynchrone via deux workers —
messenger:consume scheduler_veille(déclencheur) etmessenger:consume async(handlers de cycle). - Câblé en V1 (
e776aca), validé sur le pipeline complet.
3.3 Fetch d'article (ArticleFetcher)
- Étape ajoutée en pratique : la quasi-totalité des RSS ne fournissent que titre + lien. Sans contenu, le résumeur Claude refuse de halluciner (comportement attendu).
- Fetch lazy de l'URL puis extraction DOM (
article > main > body, strip<script>/<style>). - Contenu enrichi conservé dans
VeilleItem::raw_content(TEXT NULL — RSS si fourni, sinon résultat du fetcher).
3.4 Déduplication (entité Doctrine VeilleItem)
- Stockage : entité Doctrine
VeilleItem(pas un simple journal de hash). Justification : observabilité (queries SQL stats/source/jour), cycle de vie (pending → proposed → accepted | rejected | failed), traçabilité (model_used,tokens_in,tokens_out,error_message). - Dédup par URL OU
content_hashSHA-256 (le hash couvre les variantes avec params de tracking).
3.5 Résumé (port LLM Claude)
- Modèle V1 :
claude-haiku-4-5. Coût observé ~$0.003 / article. Température basse. - Résumé court + points clés, conservant systématiquement la source et le lien.
- Persisté sur
VeilleItem:summary,status,model_used,tokens_in,tokens_out. - Pas de prompt caching en V1 : le system prompt est < 4096 tokens, sous le seuil minimum de Haiku.
3.6 Classification (ClassifierInterface)
- V1 : règles par mots-clés derrière l'interface
ClassifierInterface. Pour le thème pilote IA : ~30 mots-clés (claude,anthropic,llm,rag,agent, …), scoring proportionnel au nombre de matches (word-boundary, fallbackdefault_themede la source si aucun match). - V2 : bascule vers embeddings du cœur (L0) lorsque dev web / juridique / qualité s'ajouteront — l'interface est là pour ça.
3.7 Écriture (proposition locale)
- Sortie : fichier Markdown
var/veille/proposals/<source>-<date>-<id>.mdcôté telaria (pas d'écriture directe danstelaria-doc/pilotage/veille/). - Frontmatter YAML :
type,title,url,source,theme,status: proposed,date,model,tokens_in,tokens_out. - Surface humaine : dashboard
/admin/veille+ revue des propositions/admin/veille/proposals(actionsaccept/reject/reopen). - Workflow de bascule vers
pilotage/veille/reste manuel en V1 (revue puis copie). Auto-push cross-repo = sujet V2 (cf. §9).
4. Périmètre V1 / hors V1
| Aspect | V1 | Hors V1 |
|---|---|---|
| Thèmes | 1 pilote (IA) | dev web, qualité, juridique |
| Collecte planifiée | ✅ (Scheduler + Messenger, cadence globale 15 min) | Cadence per-source |
| Fetch article | âś… (ArticleFetcher, fetch DOM lazy) |
— |
| Déduplication | ✅ (entité VeilleItem, url ou content_hash) |
— |
| Résumé | ✅ (Claude Haiku 4.5) | Prompt caching, scoring de pertinence avancé |
| Classification | ✅ (règles mots-clés via ClassifierInterface) |
Embeddings L0 (V2 multi-thèmes) |
| Sortie | proposition Markdown + revue humaine | publication auto, alerting, dashboard, auto-push cross-repo |
5. Gouvernance et garde-fous (critique)
- Aucune autorité juridique : une entrée de veille juridique n'affirme rien ; elle résume et pointe vers le texte officiel (CNIL, EUR-Lex). Risque d'hallucination pris au sérieux (cf. fiche 6.1).
- Sources systématiques : chaque proposition cite sa/ses source(s) avec lien (règle
AGENTS.md). - Humain dans la boucle : la sortie est une proposition, jamais une publication automatique.
- Respect des sources : conditions d'utilisation /
robots, pas de copie intégrale (résumé + lien). - Pas de données personnelles ingérées.
6. Configuration
La configuration est DB-driven : la liste des sources vit en base (entité VeilleSource), administrée via /admin/veille/sources. Seuls les paramètres applicatifs (modèle Claude, chemin de sortie) restent en config Symfony.
6.1 Entité VeilleSource (administrée via CRUD)
| Champ | Type | Usage |
|---|---|---|
slug |
string unique | Clé stable (dédup, tag, nom de fichier proposal) |
name |
string | Libellé affiché |
url |
string | URL du flux |
type |
enum rss|atom|html |
Format (html réservé V2) |
schedule |
string ISO 8601 | Cadence de collecte (ex. PT1H, PT6H) |
default_theme |
string | Thème de repli si la classification ne match rien |
is_active |
bool | Permet de couper un flux sans toucher au code |
editorial_description |
text markdown | Note de l'éditeur (pourquoi cette source, angle attendu) |
created_at / updated_at |
timestamps | Traçabilité |
Le champ type=native|community (cf. §3.1) reste pertinent pour le monitoring mais peut être porté par editorial_description ou un sous-champ — à arbitrer à l'implémentation s'il n'est pas déjà présent.
6.2 Config applicative (Symfony)
veille.model: modèle Claude pour le résumé (V1 :claude-haiku-4-5).veille.output_dir: destination des propositions (V1 :var/veille/proposals/).veille.dedup: stratégie (V1 :urlOUcontent_hashSHA-256).
7. Tests unitaires (cas concrets)
État V1 telaria : 25 tests PHPUnit verts couvrant les axes ci-dessous (planification incluse depuis e776aca).
Collecte
- Un flux RSS et un flux Atom de fixture sont parsés → items normalisés (titre, lien, date, contenu).
- Une source injoignable (erreur HTTP) ou un XML invalide est gérée proprement (log + skip), sans casser le run.
Fetch d'article
- Une URL renvoyant une page HTML standard → contenu extrait (
article > main > body), scripts/styles strippés. - Une URL en erreur (404, timeout) → item marqué
failed, pas de résumé tenté.
Déduplication
- Un item déjà traité (même
urlou mêmecontent_hashSHA-256) n'est pas re-soumis au résumé. - Cas tracking params : deux URL avec params de tracking différents mais même contenu → dédup par
content_hash.
Résumé (Claude mocké)
- Le résumé conserve la source et le lien ; la longueur est bornée.
status,summary,model_used,tokens_in,tokens_outpersistés surVeilleItem.
Classification
- Un item est rangé dans le bon thème via matches mots-clés (word-boundary).
- Matches multiples → score proportionnel, thème dominant retenu.
- Aucun match → fallback
default_themede laVeilleSource.
Écriture
- La sortie est une proposition (
status: proposeden frontmatter), pas une écriture publiée ; un humain valide. - La source est citée systématiquement.
Garde-fous
- Une entrée juridique contient un lien vers le texte officiel ; aucune affirmation sans source (couvert implicitement par le contrat « source citée + status proposed »).
Planification
- La tâche est déclenchée à la cadence globale 15 min (Scheduler
veille) et traitée par les workersmessenger:consume scheduler_veille+async.
8. Production documentaire d'accompagnement (doctrine)
| Concept introduit | Forme | Emplacement | Statut |
|---|---|---|---|
| Veille automatisée (Symfony Scheduler + Messenger) | Tuto | veille-automatisee-symfony.md |
âś… produit |
| Automatisation IA encadrée (humain dans la boucle) | renvoi fiches 4.5 / 10.5 | agents/ (existant) |
— |
9. Points tranchés et restant ouverts
9.1 Tranchés (implémentation V1 telaria)
Liste initiale des sources du thème pilote (IA).→ 10 flux RSS/Atom, catalogueia-veille-sources.md§3.Stockage des items traités.→ entité DoctrineVeilleItem(cf. §3.4) ; pas un journal de hash.Classification : règles vs embeddings.→ClassifierInterface+ règles mots-clés V1 ; embeddings reportés V2 (cf. §3.6).Format de la proposition.→ Markdown + frontmatter YAML dansvar/veille/proposals/côté telaria (cf. §3.7) ; bascule manuelle verspilotage/veille/en V1.Gestion des sources.→ entité DoctrineVeilleSource+ admin CRUD/admin/veille/sources(cf. §6.1), pas de YAML.Modèle Claude.→claude-haiku-4-5, pas de prompt caching V1 (system prompt sous le seuil 4096 tok de Haiku).Périmètre code.→ in-appsrc/Veille/, pas bundle.
9.2 Restant ouverts
- Cadence per-source : champ
VeilleSource.schedule(ISO 8601) actuellement informatif — V1 applique une cadence globale 15 min. À activer en V2. - Workflow cross-repo auto-push : actuellement la bascule des propositions
telaria/var/veille/proposals/→telaria-doc/pilotage/veille/est manuelle. Auto-push (vers une sous-arbo_inbox/) à étudier en V2 — pour l'instant le rituel manuel est sain. Monitoring des flux communautaires : seuil d'alerte et procédure de bascule si un repo upstream est abandonné.→ couvert par le standby de source (cf. §10.2) : bascule automatique après N échecs consécutifs.- Filtrage arXiv : volume très élevé sur
cs.AIbrut. En V1 le classifier mots-clés filtre déjà , mais à calibrer (embeddings ciblés en V2). - Calibrage Hacker News : ajuster le seuil
points=après quelques jours pour équilibrer signal/bruit.
10. Diagnostic & pilotage (back-office, v0.5.0)
Ajouts post-V1 livrés en prod 2026-06-01 (telaria v0.5.0). Objectif : statuer sur un flux sans fouiller les logs. Source : rétro-doc Lead dev (#28). Détails de schéma (types de colonnes exacts) = implémentation telaria ; cette spec fige le comportement et les contrats.
10.1 Journal par tentative (VeilleAttempt)
Chaque passage du pipeline sur un item est tracé dans une entité dédiée VeilleAttempt (distincte de VeilleItem, qui porte le cycle de vie de l'item). Une tentative enregistre au minimum :
- l'étape atteinte du pipeline et sa durée ;
- le diagnostic du fetch HTTP (code, erreur réseau le cas échéant) ;
- la requête et la réponse brutes de Claude (pour rejouer/auditer un résumé douteux) ;
- l'erreur complète en cas d'échec.
Bénéfice : observabilité par requête SQL (statuer sur un flux, une source, un jour) sans recourir aux logs applicatifs.
10.2 Standby de source
Une source qui échoue N fois consécutivement (seuil configurable VEILLE_SOURCE_STANDBY_THRESHOLD, défaut 3) bascule automatiquement en état standby :
standbyest un état distinct deis_active:is_active= interrupteur humain (l'éditeur a activé/désactivé la source) ;standby= mise en retrait automatique sur échecs répétés. Les deux ne se confondent pas.- Une source en
standbysort du cycle de collecte et est signalée « à statuer » au dashboard, avec un bouton « Lever la veille ». - Période de grâce : lever le standby réinitialise la série d'échecs (le compteur repart de zéro), évitant une rebascule immédiate.
10.3 Page de proposition unique
La revue d'une proposition fusionne sur une seule page l'éditorial (résumé + actions accepter/rejeter) et le diagnostic dépliable (tentatives, cf. §10.1). L'ancienne route /detail est supprimée (un clic en moins).
10.4 Composant de pagination réutilisable
Pagination factorisée dans templates/components/_pagination.html.twig (fenêtre glissante : première · précédente · … · ±5 · … · suivante · dernière). Réutilisable par toute liste paginée du back-office.
Documents liés
- Cadre :
specs/ia-vitrine.md - Catalogue des sources V1 et réserve V2+ :
ia-veille-sources.md - Veille existante (destination) :
pilotage/veille/README.md - Cœur RAG (embeddings réutilisables) :
specs/ia-coeur.md - Fiche agents — agents & automatisation :
agents/4-interagir-avec-l-ia/4-5-les-agents-ia-et-l-automatisation-de-taches.md - Fiche agents — veille et ressources :
agents/10-perspectives-et-tendances/10-5-se-former-en-continu-veille-et-ressources.md
Implémentation
| Aspect | Localisation |
|---|---|
| Bundle principal | tlr-codexia — domaine src/Veille/ dans telaria-app (in-app, pas bundle séparé) |
| Entités | VeilleSource, VeilleItem, VeilleAttempt, VeilleRead dans tlr-codexia |
| Scheduleur | Symfony Scheduler — Schedule "veille" cadence globale 15 min |
| Workers Messenger | messenger:consume scheduler_veille + messenger:consume async |
| Composants | ArticleFetcher, ClassifierInterface (règles mots-clés V1) |
| Sortie | var/veille/proposals/<source>-<date>-<id>.md côté telaria-app |
| Dashboard | /admin/veille + revue propositions /admin/veille/proposals dans telaria-app |
| LLM | claude-haiku-4-5 (résumé), via port LLM abstrait |
| Tests | 25 tests PHPUnit verts (commits 0e26ea0..e776aca) |
Historique des décisions
| Version | Date | Décision |
|---|---|---|
| 1.0 | 2026-06-14 | Version initiale — première formalisation du versioning des specs. |
| — | 2026-06-01 | V1 complète bout-en-bout livré en prod (telaria v0.5.0). Pipeline planifié actif, dashboard /admin/veille, revue propositions. |
| — | 2026-06-01 | Diagnostic v0.5.0 ajouté : VeilleAttempt (journal par tentative), standby source (N échecs consécutifs), page proposition unique, pagination réutilisable. |
| — | 2026-06-01 | Domaine veille = in-app src/Veille/, pas bundle. Extraction telaria/veille-bundle si un autre projet en a besoin. |
| — | 2026-06-01 | Modèle Claude figé : claude-haiku-4-5, pas de prompt caching V1 (system prompt < 4096 tokens, sous le seuil Haiku). |