diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml index 550039b..b748ed5 100644 --- a/.gitea/workflows/ci.yml +++ b/.gitea/workflows/ci.yml @@ -310,10 +310,21 @@ jobs: - name: Tests générateur Audit 5D run: python3 -m unittest discover -s tests -v + seo-tests: + name: SEO · mots-clés trilingues + schema.org + hreflang + runs-on: ubuntu-latest + defaults: + run: + working-directory: 05_deliverables_mvp/seo + steps: + - uses: actions/checkout@v4 + - name: Tests générateur SEO + run: python3 -m unittest discover -s tests -v + gate: name: Gate qualité (agrégat) runs-on: ubuntu-latest - needs: [constraints-guard, validate-json, check-docs, publiciste-tests, rbac-tests, faisabilite-gen-tests, rbac-fixtures-tests, rbac-userperm-tests, rbac-roleprofile-tests, rbac-applyplan-tests, bancable-tests, crm-workflow-vente-tests, crm-dossier-vente-tests, crm-commissions-tests, fiscal-ecf-tests, frontend-portails-tests, legal-confotur-tests, qa-audit-5d-tests] + needs: [constraints-guard, validate-json, check-docs, publiciste-tests, rbac-tests, faisabilite-gen-tests, rbac-fixtures-tests, rbac-userperm-tests, rbac-roleprofile-tests, rbac-applyplan-tests, bancable-tests, crm-workflow-vente-tests, crm-dossier-vente-tests, crm-commissions-tests, fiscal-ecf-tests, frontend-portails-tests, legal-confotur-tests, qa-audit-5d-tests, seo-tests] steps: - name: Résultat run: echo "✅ Gate qualité 4Big franchi — tous les checks verts." diff --git a/05_activity_log/2026-07-30.md b/05_activity_log/2026-07-30.md index f43c779..c43ae1c 100644 --- a/05_activity_log/2026-07-30.md +++ b/05_activity_log/2026-07-30.md @@ -1,5 +1,60 @@ # Activity Log · 2026-07-30 · Claude Code DTP +## Session `20260730_085719` (session 18) + +**Tâche** : **Sprint 6 · SEO** — Générateur **SEO trilingue** (roadmap L60 : +« Refactor mission `seo_autonome/` → **200+ mots-clés FR/EN/ES · schema.org · +hreflang** »). Premier volet Sprint 6 réalisable en repo — les volets OTOIA voice +Amélie (pilote AEC) et chat OTOIA embarqué dépendent d'API externes / desk VPS +(hors périmètre worker · #8). + +**Décision d'architecture** : livrable de **second niveau** — la matière première +est **`projets_master.json`**, la sortie canonique du **Publiciste** (dérivée de +`data_room/PXX/`). Le générateur ne fabrique aucun fait de projet ; il **réutilise** +(zéro duplication · #5) le validateur maison + les tokens de marque du Publiciste +(`lib/validator.py`, `lib/branding.py`). + +**Fichiers créés** — `05_deliverables_mvp/seo/` : +- `seo_spec.json` (config site + **lexique éditorial générique** FR/EN/ES + org + schema.org + cibles · zéro donnée projet, zéro chiffre) +- `seolib/{__init__,deps,keywords,schemaorg,hreflang,builder}.py` (`deps` réutilise + validateur + branding Publiciste ; `keywords`/`schemaorg`/`hreflang` purs et + déterministes ; `builder` assemble bundle + manifeste) +- `seo_gen.py` (CLI `build`/`validate` · **15 invariants**) +- `seo.schema.json` (contrat de sortie draft-07) +- `fixtures/projets_master.json` (test only · 9 projets P01..P09, noms sourcés + `CLAUDE.md §Projets`, tous `en_developpement`, **zéro chiffre**) +- `out/{seo_keywords,seo_schema_org,seo_hreflang,MANIFEST}.json` (hand-off) · + `tests/test_seo.py` (**36 tests** dont 8 injections négatives) · `README.md` · + `.gitignore` + +**Fichiers modifiés** : +- `.gitea/workflows/ci.yml` : job `seo-tests` + ajout au `gate`. + +**Anti-invention (cœur · #6)** : un mot-clé = composition de tokens factuels +(`projet:.nom`/`.localisation`, sourçables) + lexique éditorial générique +non chiffré (`lexicon:*`) ; un invariant vérifie que chaque mot-clé est sourcé et +résoluble ; un mot-clé ne peut porter que les chiffres de son champ source +(« 1069 Crisfer » passe ; un prix injecté est refusé). schema.org n'émet un prix +que pour un projet `disponible` à typologie **sourcée** (USD · #10) — la fixture +`en_developpement` produit donc **0 offre**, aucun chiffre inventé dans le hand-off. + +**Résultat** : **258 mots-clés** (fr=87 · en=87 · es=84 · cible 200 dépassée) · +schema.org 10 nœuds (1 Organization + 9 Residence) · hreflang 10 pages (accueil + +9 projets) × 4 alternates (FR/EN/ES + x-default). + +**Vérifs** : 36/36 tests ; gate CI local vert (guard + JSON + docs + YAML) ; +régression **377 tests verts** au total (341 → +36) ; build déterministe. + +**Hors périmètre worker (VPS · #8)** : injection balises hreflang/JSON-LD dans +`www/` + sitemap + Google Search Console + branchement sur la vraie sortie +Publiciste (9 projets réels) → agent SEO / Frontend. + +**Détail complet** : voir +[`05_deliverables_mvp/daily_reports/2026-07-30-session18.md`](../05_deliverables_mvp/daily_reports/2026-07-30-session18.md). + +**Auto-score 4Big** : 96/100. + ## Session `20260730_082714` (session 17) **Tâche** : **Sprint 5 · QA** — Générateur de l'**Audit 5D de conformité** diff --git a/05_deliverables_mvp/daily_reports/2026-07-30-session18.md b/05_deliverables_mvp/daily_reports/2026-07-30-session18.md new file mode 100644 index 0000000..24706f4 --- /dev/null +++ b/05_deliverables_mvp/daily_reports/2026-07-30-session18.md @@ -0,0 +1,94 @@ +# Rapport de session · 2026-07-30 · session 18 + +## Tâche + +**Sprint 6 · SEO** — Générateur **SEO trilingue** (mots-clés FR/EN/ES + +schema.org + hreflang). Roadmap L60 : « Refactor mission `seo_autonome/` → +**200+ mots-clés FR/EN/ES · schema.org · hreflang** ». + +Sprint 5 étant clos en repo (ONAPI/Legal session 16 · QA Audit 5D session 17, +Mobile hors périmètre VPS · #8), c'est le premier volet Sprint 6 réalisable dans +le repo. Les deux autres volets Sprint 6 (OTOIA voice Amélie pilote AEC · chat +OTOIA embarqué) dépendent d'API externes / du desk VPS → hors périmètre worker. + +## Décision d'architecture + +Le SEO est un livrable de **second niveau** : sa matière première est +**`projets_master.json`**, la sortie canonique du **Publiciste** (elle-même +dérivée de `data_room/PXX/` via le contrat `projets_master.schema.json`). Le +générateur **ne fabrique aucun fait de projet** — il compose du SEO à partir de +données déjà sourcées + un lexique éditorial générique non chiffré. + +Ce choix respecte #6 (zéro invention) et #5 (zéro duplication) : le générateur +**réutilise** le validateur maison et les tokens de marque du Publiciste +(`lib/validator.py`, `lib/branding.py` → `STATUTS_SANS_PRIX`, devise USD), sans +les réimplémenter. + +## Fichiers créés — `05_deliverables_mvp/seo/` + +- `seo_spec.json` — config site (base_url, langs FR/EN/ES, préfixes, x-default) + + **lexique éditorial générique** (immobilier / à vendre / résidence / pays / + régime CONFOTUR) + org schema.org + cibles. **Zéro donnée de projet, zéro + chiffre.** +- `seolib/{__init__,deps,keywords,schemaorg,hreflang,builder}.py` + - `deps` réutilise validateur + branding Publiciste ; `slugify`/`digits` + déterministes. + - `keywords` : génération déterministe, chaque mot-clé porte `scope`, `projet`, + `intent`, `category` et une liste `sources` non vide. + - `schemaorg` : graphe JSON-LD (`Organization` + une `Residence`/projet), + `offers` **uniquement** si projet disponible + prix sourcé (USD). + - `hreflang` : `alternate` FR/EN/ES + `x-default` par page. +- `seo_gen.py` — CLI `build`/`validate` · **15 invariants** de cross-cohérence + et d'anti-invention. +- `seo.schema.json` — contrat de sortie draft-07 (bundle keywords + schema.org + + hreflang + manifest). +- `fixtures/projets_master.json` — entrée **de test** : 9 projets P01..P09 (noms + sourcés de `CLAUDE.md §Projets`), tous `en_developpement`, **sans aucun chiffre**. +- `out/{seo_keywords,seo_schema_org,seo_hreflang,MANIFEST}.json` (hand-off) · + `tests/test_seo.py` (**36 tests** dont 8 injections négatives) · `README.md` · + `.gitignore`. + +## Fichiers modifiés + +- `.gitea/workflows/ci.yml` : job `seo-tests` + ajout au `gate`. + +## Anti-invention (cœur · #6) + +- Un **mot-clé** = composition de *tokens factuels* (`projet:.nom` / + `.localisation`, sourçables) et de *lexique éditorial* (`lexicon:*`, générique + non chiffré). Un invariant vérifie que chaque mot-clé est **sourcé et + résoluble**. +- Un mot-clé **ne peut porter que les chiffres présents dans son champ projet + source** : « 1069 Crisfer » (P09) passe ; un prix injecté (`… 250000`) est + **refusé** par l'invariant #7 (test négatif dédié). +- **schema.org** n'émet une `offers`/`price` **que** pour un projet `disponible` + dont une typologie porte un `prix_depuis_usd` **numérique sourcé** ; devise + **USD** (#10). Pour tout statut sans prix : **aucun chiffre** (invariant #11 + + tests). La fixture livrée (9 projets `en_developpement`) produit donc + **0 offre** — aucune valeur inventée dans le hand-off committé. + +## Résultat + +- **258 mots-clés** — fr=87 · en=87 · es=84 (cible roadmap 200 dépassée) ; +- schema.org : **10 nœuds** (1 Organization + 9 Residence), 0 offre ; +- hreflang : **10 pages** (accueil + 9 projets), 4 `alternate`/page (FR/EN/ES + + x-default). + +## Vérifs + +- **36/36 tests** SEO verts (dont oracle `jsonschema` si présent) ; +- gate CI local vert : guard contraintes · JSON bien formés · docs (liens + + score) · YAML valide ; +- **régression 377 tests verts** au total (341 → +36), 0 module en échec ; +- build déterministe (test dédié : deux builds identiques). + +## Hors périmètre worker (VPS · #8) + +- Injection des balises `` + `