Durcissement d'uniformité (pas bug déclenchable aujourd'hui) qui COMPLÈTE le fix
correctness de la session 070054 (aeb30b8). Ce fix-là a percent-encodé
hero['fichier'] dans src=f"/static/projets/{code}/{quote(fichier)}", mais dans la
MÊME url('…') CSS il restait un 2ᵉ segment dynamique — `code` — interpolé brut puis
html-échappé via _esc(src). C'est exactement l'anti-pattern identifié par 070054
(html.escape = mauvais encodeur pour un segment d'URL), appliqué de façon incomplète.
Fix : src = f"/static/projets/{quote(code)}/{quote(hero['fichier'])}" — quote() est
le SEUL encodeur correct pour un segment d'URL ; le CONTEXTE, pas la donnée courante,
dicte l'encodeur. Zéro dérive : codes réels = P01..P09 (§Projets), quote("p01")=="p01"
→ byte-repro inchangé. Cas frère exact de 060044/criteria.py (« durcir le SEUL membre
non-durci d'une famille ») : ici le SEUL segment d'URL non-encodé de la même url().
Test à dents (test_hero_media_code_segment_percent_encoded) : code théorique "P'X" →
prouvé FAIL sans quote(code), PASS avec. Suite publiciste 25→26, matrice 630/613→631/614.
Défaut d'abord : classe encodage-contextuel balayée sur tous les modules HTML/CSS/URL ;
2 candidats Explore réfutés non-défauts (chat mount_html = persona forcée Amélie par
invariant 7 + portail_key enum ; code segment = théorique mais durci par uniformité).
Cascade régénérée dans l'ordre (quality_report en DERNIER) · 3 fiches compteurs réalignées.
run_ci 33/0/0 · NFC-clean · zéro code moteur V18 (bloqué D-06 #6) · zéro gate (#5) · zéro invention (#6).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
7.0 KiB
🎯 Publiciste Agent · Maintenance automatique site public (vente.otov7.com)
Rôle : Cet agent OTOIA maintient automatiquement à jour le site public vente.otov7.com à partir des faisabilités canoniques de chaque projet. Il élimine le besoin d'édition manuelle du site.
Mission
-
Extraire en continu depuis les faisabilités canoniques (
data_room/PXX/) :- Positionnement marketing
- Typologies + surfaces
- Prix "à partir de" par typologie
- Grille tarifaire complète
- Ce qui est inclus (services · équipements · CONFOTUR · Fideicomiso · etc.)
- Rendus visuels (60_photos_site)
- Statut (Disponible · En développement · Bientôt · En processus)
-
Générer copy multilingue FR/EN/ES à partir du positionnement documenté
-
Publier automatiquement sur
vente.otov7.comsans intervention humaine -
Détecter changements dans faisabilités et déclencher rebuild du site
-
Ajouter automatiquement les nouveaux projets dès que
data_room/PXX/créé + faisabilité complète
Sources de vérité (dans l'ordre)
/opt/oto/data_room/PXX/50_financier_bancable/one_pager_banquier.pdf/opt/oto/data_room/PXX/40_llm_outputs/commercial.md/opt/oto/data_room/PXX/40_llm_outputs/marche_analyste.md/opt/oto/data_room/PXX/40_llm_outputs/directeur.md/opt/oto/data_room/PXX/00_brief//opt/oto/data_room/PXX/60_photos_site/(rendus)
Règles absolues (interdits)
- ❌ Zéro invention de prix, chiffres, positionnement (source ONLY = faisabilité)
- ❌ Jamais éditer directement
vente.otov7.com/index.html— passer par le générateur - ❌ Ne pas publier un projet dont la faisabilité est incomplète (marquer "En développement")
- ❌ Ne pas dupliquer rendus AI (source unique data_room/PXX/60_photos_site/)
Workflow détaillé
Trigger 1 : Faisabilité mise à jour
- Détecte modification dans
data_room/PXX/40_llm_outputs/*.md - Re-extrait positionnement + prix
- Régénère section projet dans
vente.otov7.com/index.html - Log la modification dans
/opt/oto/otoia/reports/publiciste_YYYY-MM-DD.md - Notifie Michel via WhatsApp si prix / positionnement change
Trigger 2 : Nouveau projet créé
- Détecte création
data_room/PXX/(nouveau code projet) - Attend que la faisabilité soit complète (score ≥ 95/100)
- Ajoute automatiquement la card projet sur vente.otov7.com
- Copie les rendus dans
/opt/oto/sites/static/projets/pXX/ - Log + WhatsApp notification
Trigger 3 : Nouveau rendu généré
- Détecte nouveau rendu dans
data_room/PXX/60_photos_site/ - Copie vers
/opt/oto/sites/static/projets/pXX/ - Met à jour l'image hero de la card si c'est le rendu principal
- Cache-bust Cloudflare automatique
Trigger 4 : Faisabilité incomplète
- Détecte "prix non documenté" ou "pricing non défini"
- Marque le projet en "En développement" avec "Prochainement · Détails à venir"
- Log + WhatsApp à Michel pour compléter faisabilité
Architecture technique
data_room/PXX/ ────► parser.py (extraction) ────► projets_master.json
│
▼
generator.py (rendu HTML)
│
▼
/opt/oto/sites/vente/index.html
│
▼
Cache-bust Cloudflare + notify Michel
Composants à créer
otoia/capabilities/publiciste.py— orchestrateur agentotoia/capabilities/knowledge/site_public_template.md— template génération site- Systemd timer
otoia-publiciste.timer(check horaire) - Watch inotify sur
data_room/*/40_llm_outputs/(temps réel) - Backend Frappe DocType
Publiciste Logpour audit trail
Livrable Publiciste réellement produit (05_deliverables_mvp/publiciste/)
Les « Composants à créer » ci-dessus décrivent le runtime VPS cible
(otoia/capabilities/publiciste.py, systemd/inotify · hors périmètre worker · CLAUDE.md #8).
Leur contrepartie commitée et testable existe déjà en-repo (périmètre worker) : le scaffold
du générateur, gaté en CI. C'est le seul module net-neuf du mandat, sur le chemin critique
(cf. ../../05_deliverables_mvp/GAP_ANALYSIS_SPRINT1.md §3.13).
| Module | Sprint | Rôle | Entrée CLI | Job CI | Tests |
|---|---|---|---|---|---|
publiciste/ |
2 (README scaffold (Sprint 2) · GAP §3.13) |
Pipeline site public : data_room/PXX/ → projets_master.json → index.html luxury (lib/parser.py extraction · lib/validator.py schéma · lib/generator.py + lib/branding.py rendu dark+doré #0a0a12/#f0b429 · templates/site_public.html.tmpl) |
publiciste.py parse|validate|generate|run |
publiciste-tests |
26 |
Le contrat d'échange projets_master.json n'est pas défini ici mais par le Faisabilité Agent
(../../05_deliverables_mvp/faisabilite/projets_master.schema.json,
Sprint 1) — source unique, zéro duplication (#5). Le Publiciste en est le consommateur :
lib/parser.py extrait, lib/validator.py valide contre ce schéma avant tout rendu.
Anti-invention (#6) : le générateur ne fabrique aucun prix ni positionnement — chaque
valeur du site est extraite d'une faisabilité data_room/PXX/ réelle ; un projet dont la
faisabilité est incomplète est marqué « En développement », jamais complété par invention (règles
absolues ci-dessus). Aucun index.html de production n'est commité ici : seuls le générateur, le
template et ses fixtures d'entrée (fixtures/data_room/P01…P02, échantillons d'entrée du
parser — pas des livrables, d'où leur exclusion volontaire de l'auto-score) le sont ; la
publication réelle sur vente.otov7.com s'exécute côté VPS (#8). Auto-score du livrable :
95/100 (README.md).
Livrable Sprint (mandat 8 semaines)
- Semaine 2 : Setup base + parser faisabilité → JSON
- Semaine 3 : Générateur HTML → vente.otov7.com
- Semaine 4 : Triggers systemd + inotify actifs
- Semaine 5 : Notifications WhatsApp Michel
- Semaine 6 : Multi-langue FR/EN/ES automatique
- Semaine 7 : Tests + validation faisabilités P01-P09
- Semaine 8 : Production
Coordination inter-agents
- BIM Agent : fournit rendus (Blender/Bonsai → 60_photos_site)
- Faisabilité Agent : génère faisabilités 4 volets → 40_llm_outputs
- Rendu Agent : batch renders → 60_photos_site
- CRM Agent : reçoit leads/inscriptions du site public
- SEO Agent : optimise les balises meta générées