# Design — Skill `seo-audit-semantique`

**Date** : 2026-07-29
**Statut** : validé en brainstorming, prêt pour plan d'implémentation
**Origine** : extraction et refonte du « Mode Audit » de `seo-preparation-semantique.md` (lignes 419-453)

---

## 1. Problème

Le mode Audit existe aujourd'hui comme appendice de 35 lignes à la fin d'un document de 453 lignes conçu pour la création. Neuf défauts le rendent non exécutable de façon reproductible.

| # | Défaut | Gravité |
|---|---|---|
| 1 | Aucune phase n'a de format Audit spécifié — « 3 colonnes au lieu d'une » est inapplicable à un tableau qui en a déjà 7 | Bloquant |
| 2 | Score « X/11 couches » adossé à un dénominateur jamais défini (le pipeline compte 16 livrables) | Bloquant |
| 3 | Contradiction interne : le doc alerte sur la saturation de contexte, or l'Audit est le mode le plus vorace et le moins délégué | Haute |
| 4 | « Couvert » binaire alors que la carte exige une densité en % — le comptage, pourtant déterministe, n'est pas prescrit | Haute |
| 5 | Trois phases inauditables (0, 7, 13) passées au même moule que les autres | Haute |
| 6 | Les P0 portent sur des champs (title, meta, schema) absents du Markdown et du texte collé → faux positif structurel | Haute |
| 7 | Aucune sortie machine : pas de suivi dans le temps, incohérent avec `seo-eeat` qui produit un sidecar JSON | Moyenne |
| 8 | Input « version cible » demandé sans aucun effet documenté | Moyenne |
| 9 | Pas de re-audit : « mes P0 sont-ils réglés ? » impose de repartir de zéro | Moyenne |

### Points forts à préserver

- Le triptyque **Attendu / Couvert / Gap**, qui force la génération de la référence avant la lecture du contenu.
- Le statut **⚠️ Hors scope**, qui produit des actions de suppression là où le marché ne produit que des ajouts.
- La priorisation **P0/P1/P2 adossée à la Triade SERP**, explicable sans jargon.
- Le **Surprise Score 0-100**, chiffre avant/après comparable.
- Les garde-fous anti-hallucination : **Confidence Score**, **Freshness Guard**, `[À SOURCER]`.
- **Zéro dépendance externe** — pas de scraping SERP, pas d'API embeddings, honnêteté sur le cosinus simulé.

---

## 2. Décisions d'architecture

### 2.1 Skill séparé, carte déléguée

Deux skills frères plutôt qu'un skill à deux modes :

- `seo-preparation-semantique` — mode Création, produit la carte.
- `seo-audit-semantique` — consomme une carte, produit un plan de correction.

Motif : déclencheurs utilisateur distincts (mélanger deux familles de formulations dans un seul `description` de frontmatter dilue le matching qui décide du chargement), livrables distincts, et surtout possibilité de sortir la génération de carte du contexte principal.

### 2.2 Flux d'exécution

```
inputs : requête + profil + contenu (+ JSON d'audit antérieur si présent)
   │
   ├─ étape 0  détection de source → déclaration de périmètre
   │
   ├─ étape 1  DÉLÉGATION : sous-agent génère la carte de référence
   │           (invoque seo-preparation-semantique, contexte séparé)
   │           ⤶ ne remonte QUE la carte, en JSON compact
   │
   ├─ étape 2  chargement du contenu — une page, jamais le site
   │
   ├─ étape 3  variantes de surface par entité → comptage par script
   │
   ├─ étape 4  diff sur les 11 couches : Attendu × Mesuré × Gap
   │
   └─ étape 5  rapport .md + sidecar .json (vN, sans écrasement)
               + delta si un audit antérieur existe
```

### 2.3 Le générateur de carte est aveugle au contenu

**Contrainte non négociable.** Le sous-agent qui produit la carte de référence reçoit la requête et le profil, **jamais le contenu à auditer**.

S'il voyait le contenu, la carte s'alignerait sur ce qui est déjà écrit : l'audit ne trouverait plus rien et validerait la page par construction. C'est le mode d'échec principal d'un audit conduit par un LLM en contexte unique, et le mode Audit actuel ne s'en protège pas.

La carte remonte en JSON compact, pas en prose des 13 phases — le contexte principal reçoit une référence exploitable sans absorber le raisonnement qui l'a produite.

### 2.4 Fallback sans sous-agent

Si l'environnement ne permet pas la délégation, la carte est générée dans le contexte principal **avant** tout chargement du contenu, et le rapport porte l'avertissement : *« carte de référence produite dans le même contexte que le contenu — risque d'ancrage, gaps possiblement sous-détectés »*. Dégradé, mais jamais silencieux.

---

## 3. Les 11 couches auditables

Sur les 16 livrables du pipeline Création, 11 portent sur le contenu. Les autres portent sur la requête ou sur le marché : les auditer n'a pas de sens. Ceci définit le dénominateur qui manquait (défauts #2 et #5).

| # | Couche | Phase source | Régime |
|---|---|---|---|
| C1 | Micro-intentions couvertes | 1 | Qualitatif |
| C2 | Entités pondérées & densités | 2 | **Quantitatif** |
| C3 | Lexique signature (n-grams) | 3 | **Quantitatif** |
| C4 | Pain points & verbatims | 4 | Qualitatif |
| C5 | Preuves quantitatives | 5 | Qualitatif |
| C6 | Vecteurs multimodaux | 6 | Qualitatif |
| C7 | Couverture standard vs surprise | 8b | Dérivé de C2 |
| C8 | Divergence / Information Gain | 9 | Qualitatif |
| C9 | FAQ stratégique | 10 | Qualitatif |
| C10 | Structural GEO | 11 | Qualitatif |
| C11 | Mapping Triade SERP | 12 | Qualitatif |

**Hors audit** — produites par le sous-agent comme contexte de référence, jamais comparées au contenu :

- Phase 0 (filtre stratégique) — porte sur la requête.
- Phase 7 (cartographie concurrentielle) — porte sur le marché.
- Phase 8a (Gap Competitive Map) — porte sur les concurrents.
- Phase 13 (patches KB) — porte sur la base de connaissance de l'utilisateur.

Le **Surprise Score 8c** n'est pas une couche : c'est le score global du contenu audité, recalculé sur ses quatre composantes.

---

## 4. Périmètre selon la source

Le défaut #6 vient de ce que les P0 portent sur des champs qui n'existent que dans le HTML. La réponse est un périmètre déclaré et un dénominateur dynamique — jamais un « Gap » sur un champ non observable.

| Couche | URL / HTML | Markdown | Texte collé |
|---|---|---|---|
| C1–C5, C7–C9, C11 | ✅ | ✅ | ✅ |
| C6 multimodal | ✅ complet | 🟡 tableaux + liens images | 🟡 tableaux seuls |
| C10 structural | ✅ complet | 🟡 H1/Hn seuls — meta et schema `N/A` | ❌ `N/A` |

Règles :

- Le bloc PÉRIMÈTRE est écrit **en tête du rapport**, avant tout verdict.
- Une couche **entièrement** non observable ne compte ni au numérateur ni au dénominateur du score de couverture.
- Une couche **partiellement** observable compte au dénominateur ; seuls ses champs manquants sont listés en `na` et exclus du jugement. Exemple : sur Markdown, C10 reste évaluable sur H1/Hn, avec `C10.meta-description` et `C10.schema-org` en `na`.
- Chaque `N/A` porte sa raison et le moyen de le lever (« fournir l'URL ou le HTML rendu »).
- Jamais bloquant : l'audit produit toujours son rapport sur les couches observables.

---

## 5. Mesure

### 5.1 Couches quantitatives (C2, C3)

1. Le modèle liste les variantes de surface par entité — flexions, casse, tirets, acronymes, synonymes stricts — **et les faux positifs à écarter** (`PR` = *passage ranking* ou *public relations* selon le contexte).
2. Un script Python jetable prend `{entité: [variantes]}` + le texte et sort occurrences et total de mots en un passage. Écrit dans le scratchpad, jamais commité.
3. Densité = occurrences / total de mots × 100, comparée à la cible de la carte.

Le comptage sort du contexte parce que les LLM comptent mal les occurrences. Le travail sémantique (quelles variantes comptent) reste au modèle ; le travail arithmétique va au script.

### 5.2 Seuils de statut

Fixés pour que deux runs sur le même contenu donnent le même verdict.

| Statut | Règle |
|---|---|
| ✅ Conforme | 70 % ≤ densité mesurée ≤ 200 % de la cible |
| 🟡 Sous-densifié | 0 < densité < 70 % de la cible |
| 🟠 Sur-densifié | densité > 200 % de la cible (risque de stuffing) |
| ❌ Absent | 0 occurrence, toutes variantes confondues |
| ⚠️ Hors scope | terme absent de la carte, avec ≥ 5 occurrences ou densité ≥ 0,15 % |

### 5.3 Couches qualitatives

Jugement argumenté : chaque verdict cite le passage du contenu qui le fonde, ou constate son absence. Aucun chiffre de densité n'est produit sur ces couches. Le rapport distingue explicitement ce qui est compté de ce qui est jugé.

### 5.4 C7, dérivée

Calculée depuis C2, non mesurée séparément : pourcentage d'entités P1 conformes parmi les standards, pourcentage parmi les surprises. Verdict repris du Content Gap Score (standard ≥ 70 %, surprise ≥ 30 %).

### 5.5 Règle de contexte

Les trois règles du doc source sont conservées — une page à la fois, index léger d'abord, délégation des lectures longues — et complétées : la carte arrive en JSON, le comptage part dans un script. Le contexte principal ne porte que la comparaison.

---

## 6. Sortie

### 6.1 Fichiers

```
ma-page.md
ma-page.audit-v1.md      ← rapport lisible
ma-page.audit-v1.json    ← sidecar machine
```

`vN+1` si un `vN` existe — jamais d'écrasement, conforme à la convention du dépôt. Si la source est une URL sans fichier local, le slug dérive du domaine et du chemin.

### 6.2 Structure du rapport

```
AUDIT SÉMANTIQUE — <titre / URL> — v1 — YYYY-MM-DD
Requête : "..."   Profil : ...   Version cible : ...

== PÉRIMÈTRE ==       source, couches observables, N/A justifiés
== VERDICT ==         Surprise Score /100 + couverture X/N + décision
== DÉTAIL C1 → C11 == Attendu | Mesuré ou Constaté | Gap → Action
== HORS SCOPE ==      citations + raison + action
== PLAN P0/P1/P2 ==
== DELTA vs v(N-1) == si un audit antérieur existe
```

### 6.3 Priorisation déterministe

| Niveau | Déclencheur | Conséquence SERP |
|---|---|---|
| **P0** | Gap sur un champ **observable** de C10, ou une phase entière de la Triade non couverte (C11) | Ne franchit pas l'admission |
| **P1** | Gap sur C4, C5 ou C8 — ou Surprise Score < 60 — ou hors scope ≥ 0,5 % de densité | Indexé mais Low Surprise |
| **P2** | Gap sur C6 ou C9 — ou hors scope < 0,5 % | Ranke sans maximiser la génération |

**C10 et observabilité.** Un champ `na` ne produit jamais de P0 — sinon l'audit inventerait un bloquant sur un champ qu'il n'a pas pu lire. Deux conséquences à écrire dans le rapport :

- Si **une partie** des champs structurels est observable, le P0 se déclenche sur ceux-là uniquement ; les autres restent listés en `na`.
- Si **tous** les champs structurels sont `na` (cas du texte collé), le bloc PLAN porte la mention explicite *« P0 structurels non évaluables sur cette source — relancer avec l'URL ou le HTML rendu »*. Un plan sans P0 ne doit jamais pouvoir se lire comme « aucun bloquant ».

### 6.4 « Version cible » comme modulateur

L'input mort du défaut #8 reprend un effet observable sur la priorisation.

| Version cible | Effet |
|---|---|
| **refonte** | Priorisation standard, tous les gaps ouverts |
| **update freshness** | C5 remonte en P0 — le Freshness Guard devient le critère central ; les gaps structurels déjà conformes sont rétrogradés |
| **élargissement** | C1 (micro-intentions orphelines) et C9 remontent en P0 ; ⚠️ hors scope rétrogradé — on élargit, on ne resserre pas |
| **migration** | C10 et C11 en P0 exclusifs — l'enjeu est la préservation du retrieval, pas l'enrichissement |

Si l'utilisateur ne fournit pas de version cible, `refonte` s'applique par défaut et le rapport le mentionne.

### 6.5 Sidecar JSON et identifiants stables

Chaque constat porte un ID déterministe — `C2.entity.passage-ranking`, `C10.meta-description`, `C4.pain.<slug>`. Sans identifiants stables, le delta ne peut pas apparier deux audits et le re-audit repart de zéro.

```json
{
  "version": 1, "date": "2026-07-29", "query": "...",
  "profile": { "market": "B2B", "role": "...", "sector": "...", "target_version": "refonte" },
  "source": { "type": "markdown", "path": "...", "word_count": 2431 },
  "scope": {
    "observable": ["C1", "C2", "C3", "C4", "C5", "C6", "C7", "C8", "C9", "C10", "C11"],
    "partial": ["C6", "C10"],
    "na": [
      { "id": "C10.meta-description", "reason": "absent du Markdown" },
      { "id": "C10.schema-org", "reason": "absent du Markdown" }
    ]
  },
  "surprise_score": { "total": 42, "components": { "proprietary_entities": 0.31 } },
  "coverage": { "conforming": 6, "observable": 11 },
  "layers": {
    "C2": { "entities": [
      { "id": "C2.entity.bm25", "target_density": 0.3, "variants": ["BM25", "bm-25"],
        "occurrences": 2, "density": 0.10, "status": "sous-densifie" }
    ] }
  },
  "out_of_scope": [{ "id": "C0.oos.netlinking", "occurrences": 11, "density": 0.45 }],
  "corrections": { "P0": ["C10.meta-description"], "P1": ["C2.entity.bm25"], "P2": [] }
}
```

### 6.6 Delta de re-audit

Si un `.audit-v(N-1).json` est présent à côté du contenu, le rapport ouvre sur :

- évolution du Surprise Score ;
- P0/P1/P2 résolus vs restés ouverts, appariés par ID ;
- **régressions** — entité conforme en v(N-1) devenue sous-densifiée ;
- nouveaux hors scope apparus.

---

## 7. Arborescence

```
seo-audit-semantique/
├── SKILL.md                      # entrée courte : déclencheurs, flux, règles absolues
└── references/
    ├── layers-c1-c11.md          # format Attendu/Mesuré/Gap détaillé par couche
    ├── scoring-thresholds.md     # seuils densité, P0/P1/P2, modulateurs version cible
    ├── output-schema.md          # schéma JSON + gabarit du rapport
    └── counting-script.md        # gabarit du script de comptage
```

`SKILL.md` reste court ; le volume part en `references/`, chargé à la demande.

---

## 8. Frontière avec les skills voisins

- `seo-preparation-semantique` — produit la carte. L'Audit la consomme, ne la réimplémente pas.
- `seo-eeat` — rédaction en aval à partir de briefs Lumenia. L'Audit ne rédige pas : il produit des actions de correction, pas du texte publiable.
- `seo-geo` — optimisation pour moteurs génératifs et schema markup. Recouvrement partiel sur C10 ; l'Audit constate, `seo-geo` implémente.

**Règle** : l'Audit ne produit ni H1 final, ni hook, ni prose. Son livrable est un diagnostic priorisé.

---

## 9. Traçabilité des défauts

| Défaut | Traité par |
|---|---|
| #1 format non spécifié | §3 (régime par couche) + `references/layers-c1-c11.md` |
| #2 dénominateur fantôme | §3 (11 couches définies) |
| #3 saturation de contexte | §2.2, §2.3, §5.5 (délégation + JSON + script) |
| #4 couverture binaire | §5.1, §5.2 (comptage déterministe, 5 statuts) |
| #5 phases inauditables | §3 (liste « hors audit » explicite) |
| #6 faux positif structurel | §4 (périmètre déclaré, dénominateur dynamique) |
| #7 pas de sortie machine | §6.5 (sidecar JSON) |
| #8 input mort | §6.4 (version cible comme modulateur) |
| #9 pas de re-audit | §6.6 (delta par appariement d'ID) |

Ajout non présent dans le doc source : **§2.3 aveuglement du générateur de carte**, garde-fou contre l'auto-validation.

---

## 10. Hors périmètre de ce design

- L'écriture du `SKILL.md` et des `references/` — passe par `skill-creator` (règle globale : aucun skill écrit à la main).
- La refonte du skill `seo-preparation-semantique` lui-même, y compris la correction de son frontmatter mal placé. Sujet distinct, spec distincte.
- Tout audit multi-pages ou agrégation à l'échelle d'un site. Une page à la fois, par construction.
