# Générateur SEO trilingue · Sprint 6 · SEO Roadmap Sprint 6 · SEO (L60) : **« Refactor mission `seo_autonome/` → 200+ mots-clés FR/EN/ES · schema.org · hreflang »**. Produit un **bundle de hand-off SEO** consommé ensuite par l'agent SEO/Frontend sur le VPS. Le worker n'écrit **jamais** sur le VPS (#8) : il émet des artefacts diffables, l'injection réelle des balises et la soumission Google Search Console restent côté serveur. ## Ce que ça fait | Volet roadmap | Sortie | |---|---| | 200+ mots-clés FR/EN/ES | `out/seo_keywords.json` — **258** mots-clés (fr=87 · en=87 · es=84), chacun **sourcé** | | schema.org | `out/seo_schema_org.json` — graphe JSON-LD (`Organization` + une `Residence` par projet) | | hreflang | `out/seo_hreflang.json` — carte `alternate` FR/EN/ES + `x-default` par page | | compte-rendu | `out/MANIFEST.json` | ## Source de vérité (zéro invention · #6) La matière première est **`projets_master.json`**, la sortie canonique du [Publiciste](../publiciste/README.md) (elle-même dérivée de `data_room/PXX/` via le contrat [`projets_master.schema.json`](../faisabilite/projets_master.schema.json)). Le worker ne fabrique **aucun** fait de projet : - un **mot-clé** est une composition de *tokens factuels* (nom / localisation du projet, sourçables `projet:.`) et de *vocabulaire éditorial générique* (lexique `immobilier` / `à vendre` / … , non chiffré, `lexicon:*`) ; - un mot-clé **ne peut porter que les chiffres déjà présents dans son champ projet source** (ex. « 1069 Crisfer » est admis ; un prix inventé est refusé) ; - **schema.org** n'expose une `offers`/`price` **que** pour un projet `disponible` dont une typologie porte un `prix_depuis_usd` **numérique sourcé** dans le master ; devise **USD** (devise primaire · #10). Pour tout statut sans prix (`en_developpement` / `bientot` / `en_processus`) : **aucun chiffre**. Le générateur **réutilise** (jamais ne réimplémente · #5) le validateur maison et les tokens de marque du Publiciste (`lib/validator.py`, `lib/branding.py` : `STATUTS_SANS_PRIX`, devise USD). ## Utilisation ```bash # Génère le bundle depuis la fixture de test (9 projets P01..P09) python3 seo_gen.py build # Ou depuis la vraie sortie Publiciste (VPS) : python3 seo_gen.py build --master /chemin/projets_master.json -o out # Valide (schéma de sortie + 15 invariants) sans écrire python3 seo_gen.py validate ``` ## Garanties (15 invariants) Volume ≥ cible roadmap (200) · 3 langues couvertes, minimum par langue · unicité `(term, lang)` · chaque mot-clé sourcé et résoluble · anti-invention de chiffre · un listing schema.org par projet (nom + localité = donnée source) · offres présentes **ssi** projet disponible + prix sourcé (USD) · aucun prix pour un statut sans prix · hreflang : une page par projet + accueil, `alternate` complètes + `x-default` = langue par défaut = `canonical` · toutes les URLs sous `base_url` en `https` · compteurs du manifeste cohérents. ## Tests ```bash python3 -m unittest discover -s tests -v # 36 tests (dont 8 injections négatives) ``` ## Hors périmètre worker (VPS · #8) - Injection des balises `` + `