# Audit conformité spec SEO/IA — Implementation Plan

> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.

**Goal:** Confronter l'implémentation du site Acieb v2 à la checklist canonique de specification.website (10 catégories, required+recommended+avoid) et produire un rapport de gaps + un plan d'attaque priorisé.

**Architecture:** Pipeline en 3 vagues — (0) un harness runtime qui build/sert le site une fois et dumpe tous les artefacts observables dans `.audit/` ; (1) fan-out de 10 sous-agents catégorie en parallèle, chacun confrontant ses items spec (via MCP) au code + aux artefacts fichier ; (2) synthèse qui merge, déduplique les items transverses, contrôle la couverture, et écrit le rapport. Les sous-agents lisent uniquement des fichiers (`.audit/`) → pas de dépendance à un serveur vivant pendant la vague 1.

**Tech Stack:** Next.js 16 (App Router), pnpm, MCP `specification-website` (`get_checklist`/`list_topics`/`get_topic`), curl, `npx lighthouse`, linkinator. Spec de référence : `docs/superpowers/specs/2026-06-01-seo-ai-spec-audit-design.md`.

---

## File Structure

| Fichier | Responsabilité |
|---|---|
| `.audit/` (gitignored, jetable) | Artefacts runtime : headers, HTML dumps, lighthouse JSON, links, manifest, checklist maître, findings par catégorie |
| `.audit/checklist-master.json` | Union des items required+recommended+avoid des 10 catégories (référence couverture) |
| `.audit/manifest.json` | URLs testées + liste des artefacts produits par le harness |
| `.audit/findings-<cat>.json` | Sortie d'un sous-agent catégorie (schéma de finding) |
| `docs/seo-ai-audit/2026-06-01-report.md` | Livrable : matrice de gaps + plan d'attaque P0/P1/P2 |

---

## Task 1: Prep — dossiers & gitignore

**Files:**
- Modify: `.gitignore` (ajouter `.audit/`)
- Create: `docs/seo-ai-audit/` (dossier de sortie, versionné)

- [ ] **Step 1: Ignorer le dossier d'artefacts**

Ajouter à `.gitignore` :
```
# Audit SEO/IA — artefacts jetables
.audit/
```

- [ ] **Step 2: Créer les dossiers**

```bash
mkdir -p .audit docs/seo-ai-audit
```

- [ ] **Step 3: Vérifier**

```bash
git check-ignore .audit/ && ls -d docs/seo-ai-audit
```
Expected: `.audit/` listé comme ignoré ; `docs/seo-ai-audit` existe.

---

## Task 2: Checklist maître (référence couverture)

**Files:**
- Create: `.audit/checklist-master.json`

But : figer la liste exacte d'items à auditer, pour le contrôle de couverture en synthèse.

- [ ] **Step 1: Tirer la checklist du MCP (main thread)**

Pour chaque catégorie ∈ {foundations, seo, accessibility, security, well-known, agent-readiness, performance, privacy, resilience, i18n} :
- `list_topics(category=<cat>, status=required)` → items required
- `list_topics(category=<cat>, status=recommended)` → items recommended
- `list_topics(category=<cat>, status=avoid)` → items avoid

- [ ] **Step 2: Écrire le master**

Construire et écrire `.audit/checklist-master.json` :
```json
{
  "generated_for": "2026-06-01",
  "categories": {
    "seo": {
      "required": [{"slug": "...", "title": "..."}],
      "recommended": [{"slug": "...", "title": "..."}],
      "avoid": [{"slug": "...", "title": "..."}]
    }
    // … 9 autres catégories
  },
  "total_items": 0
}
```
Renseigner `total_items` = somme des items (required+recommended+avoid sur les 10 catégories).

- [ ] **Step 3: Vérifier**

```bash
python3 -c "import json; d=json.load(open('.audit/checklist-master.json')); print('cats:', len(d['categories']), 'total:', d['total_items'])"
```
Expected: `cats: 10` et `total` > 0 (≈ 100-130 selon required+recommended+avoid).

---

## Task 3: Harness runtime — build, serve, dump

**Files:**
- Create: `.audit/headers-*.txt`, `.audit/page-*.html`, `.audit/route-*.{txt,xml,json}`, `.audit/lh-*.json`, `.audit/links.json`, `.audit/manifest.json`

> Exécuté par le **main thread** (le serveur doit rester vivant le temps des captures ; il sera tué en fin de task). Tout est dumpé sur disque → la vague 1 n'a plus besoin du serveur.

- [ ] **Step 1: Build prod**

```bash
pnpm build 2>&1 | tail -20
```
Expected: build réussi (`content-collections build && next build`). Si échec : STOP, corriger avant de continuer (un build cassé invalide l'audit runtime).

- [ ] **Step 2: Démarrer le serveur prod (background)**

```bash
pnpm start
```
Lancer en background (port 3000). Puis attendre la disponibilité :
```bash
for i in $(seq 1 30); do curl -sf -o /dev/null http://localhost:3000 && echo READY && break; sleep 1; done
```
Expected: `READY`.

- [ ] **Step 3: Dériver les URLs représentatives depuis le sitemap**

```bash
curl -s http://localhost:3000/sitemap.xml -o .audit/route-sitemap.xml
grep -oE '<loc>[^<]+</loc>' .audit/route-sitemap.xml | sed -E 's:</?loc>::g' > .audit/all-urls.txt
```
Choisir 4 URLs types (home + 1 par grand template) : `/`, une `/guides/…`, une `/outils/…`, une `/secteurs/…` (ou `/expertise/…`). Les stocker dans `.audit/test-urls.txt` (chemins relatifs).

- [ ] **Step 4: Dump headers + HTML des pages types**

Pour chaque URL de `.audit/test-urls.txt` (slug = nom de fichier sûr) :
```bash
curl -sI  "http://localhost:3000<path>" > ".audit/headers-<slug>.txt"
curl -s   "http://localhost:3000<path>" > ".audit/page-<slug>.html"
```

- [ ] **Step 5: Dump des routes spéciales**

```bash
for r in robots.txt sitemap.xml llms.txt llms-full.txt services.md manifest.webmanifest feed.xml .well-known/security.txt; do
  code=$(curl -s -o ".audit/route-$(echo $r | tr '/' '_').txt" -w '%{http_code}' "http://localhost:3000/$r")
  echo "$r -> $code"
done | tee .audit/special-routes-status.txt
```
Noter les 404 (ex. security.txt absent = finding well-known).

- [ ] **Step 6: Lighthouse (CWV + scores) sur les URLs types**

```bash
n=0; while read -r p; do
  npx -y lighthouse "http://localhost:3000$p" --quiet --chrome-flags="--headless=new --no-sandbox" \
    --only-categories=performance,seo,best-practices,accessibility \
    --output=json --output-path=".audit/lh-$n.json" || echo "LH FAIL $p" >> .audit/lh-errors.txt
  n=$((n+1))
done < .audit/test-urls.txt
```
Si Chrome/Lighthouse indisponible : écrire `.audit/lh-errors.txt` ; les items performance seront marqués `na (non vérifiable runtime)` en synthèse (pas de faux `pass`).

- [ ] **Step 7: Liens morts (linkinator)**

```bash
pnpm check-links:json > .audit/links.json 2>/dev/null || echo '{"error":"linkinator failed"}' > .audit/links.json
```

- [ ] **Step 8: Manifest + arrêt serveur**

Écrire `.audit/manifest.json` : `{ "test_urls": [...], "special_routes": {...statuts...}, "artifacts": [...], "lighthouse": ["lh-0.json", ...], "lh_available": true|false }`. Puis tuer le serveur (`pkill -f "next start"` ou kill du PID background).

- [ ] **Step 9: Vérifier**

```bash
ls -1 .audit/ && python3 -c "import json,glob; print('artifacts:', len(glob.glob('.audit/*'))); json.load(open('.audit/manifest.json'))"
```
Expected: manifest valide, HTML dumps + headers + au moins les routes spéciales présents.

---

## Task 4: Fan-out — 10 sous-agents catégorie (parallèle)

**Files:**
- Create: `.audit/findings-<cat>.json` (un par catégorie)

> **Subagent max** : dispatcher les 10 agents EN PARALLÈLE (un seul message, 10 appels Agent). Chaque agent est autosuffisant et ne lit que des fichiers + le MCP.

- [ ] **Step 1: Dispatcher les 10 agents**

Pour chaque catégorie, lancer un sous-agent (type `Explore` ou `general-purpose`) avec ce prompt paramétré :

```
Tu audites la catégorie spec "<CAT>" du site Acieb v2 (Next.js App Router, repo cwd).
Référentiel : MCP specification-website. Artefacts runtime : dossier .audit/ (déjà produit).

1. Récupère tes items via le MCP :
   - get_checklist(category="<CAT>", status="required")
   - get_checklist(category="<CAT>", status="recommended")
   - list_topics(category="<CAT>", status="avoid")
   Pour tout item ambigu, get_topic(slug) pour lire le critère exact.

2. Confronte CHAQUE item au site :
   - Code : <FILE_MAP de la catégorie — cf. spec §"Map catégorie → zone du site">
   - Runtime : lis les fichiers pertinents dans .audit/
     (headers-*.txt, page-*.html, route-*.txt, lh-*.json, links.json, special-routes-status.txt)

3. Pour un item "avoid" : verdict=fail s'il EST présent (anti-pattern à retirer).

4. Renvoie UNIQUEMENT un JSON conforme :
   {"category":"<CAT>","findings":[
     {"slug","title","status":"required|recommended|avoid",
      "verdict":"pass|partial|fail|na",
      "evidence":"file:line | header servi | métrique LH (preuve OBLIGATOIRE si pass)",
      "gap":"ce qui manque","fix":"action + fichier cible","effort":"S|M|L"}]}
   Couvre TOUS tes items (un finding par slug). Aucune prose hors JSON.
```

Utiliser le schéma `schema` (StructuredOutput) si dispatch via workflow, sinon parser le JSON renvoyé. Écrire chaque sortie dans `.audit/findings-<cat>.json`.

File maps (rappel, depuis le spec) :
- foundations → `app/layout.tsx`, `app/**/page.tsx`, favicons (`app/icon*.tsx`, `manifest.ts`)
- seo → metadata+canonical, `app/sitemap.ts`, `app/robots.ts`, `lib/json-ld.tsx`, OG/Twitter, `app/feed.xml/`
- agent-readiness → `app/llms.txt|llms-full.txt|services.md`, robots bots IA, JSON-LD, structure MDX
- well-known → `/.well-known/*`, robots.txt, sitemap.xml (cf. `.audit/route-*`)
- security → headers `next.config.ts` vs headers servis (`.audit/headers-*.txt`)
- performance → `.audit/lh-*.json`, `next.config.ts` (images/cache), fonts, `app/globals.css`
- accessibility → `.audit/page-*.html`, `components/ui/`, `app/layout.tsx`
- privacy → `lib/cookieconsent/`, `components/cookie-consent/`, gating `lib/analytics.ts`/`lib/openpanel.ts`
- resilience → `app/error.tsx`, `app/not-found.tsx`
- i18n → `<html lang>`, hreflang, `content-language` (site FR mono-locale)

- [ ] **Step 2: Vérifier les 10 sorties**

```bash
ls -1 .audit/findings-*.json | wc -l
for f in .audit/findings-*.json; do python3 -c "import json,sys; d=json.load(open('$f')); print('$f', len(d['findings']), 'findings')"; done
```
Expected: 10 fichiers, chacun avec des findings. Si un agent a échoué/JSON invalide : le relancer (un seul agent, même prompt).

---

## Task 5: Synthèse — rapport + plan d'attaque

**Files:**
- Create: `docs/seo-ai-audit/2026-06-01-report.md`

- [ ] **Step 1: Merge + contrôle de couverture**

Charger les 10 `findings-*.json` + `.audit/checklist-master.json`. Vérifier que chaque slug du master a exactement un finding. Lister tout slug manquant ou en double.
```bash
python3 - <<'PY'
import json, glob
master = json.load(open('.audit/checklist-master.json'))
want = {(c, i['slug']) for c, b in master['categories'].items() for k in ('required','recommended','avoid') for i in b.get(k, [])}
got = {}
for f in glob.glob('.audit/findings-*.json'):
    d = json.load(open(f))
    for x in d['findings']:
        got[(d['category'], x['slug'])] = x['verdict']
missing = want - set(got)
extra = set(got) - want
print('master:', len(want), 'covered:', len(got & set(want)), 'missing:', len(missing), 'extra:', len(extra))
for m in sorted(missing): print('  MISSING', m)
PY
```
Expected: `missing: 0`. Si >0 : relancer l'agent de la catégorie concernée pour combler.

- [ ] **Step 2: Déduplication des items transverses**

Pour les slugs qui apparaissent dans 2 catégories (canonical, lang, headers de cache/sécurité…), garder un verdict unique (le plus sévère) et noter les catégories concernées. Documenter la règle appliquée dans le rapport.

- [ ] **Step 3: Écrire le rapport**

`docs/seo-ai-audit/2026-06-01-report.md` structure :
```markdown
# Audit SEO/IA — Conformité specification.website — 2026-06-01

## Score de couverture
Items audités : N/N (100%). Lighthouse : dispo/indispo.

## Matrice par catégorie
### <catégorie>
| slug | statut | verdict | preuve | correctif | effort |
|------|--------|---------|--------|-----------|--------|
(… une ligne par item, ✅ pass / ⚠️ partial / ❌ fail / �o na …)

## Plan d'attaque priorisé
### P0 — required en échec (indexation/contrat menacé)
- [ ] <slug> — <action> — `fichier cible` — effort S/M/L
### P1 — recommended en échec
- [ ] …
### P2 — avoid présents + durcissements
- [ ] …
```

- [ ] **Step 4: Vérifier**

```bash
test -f docs/seo-ai-audit/2026-06-01-report.md && grep -c '|' docs/seo-ai-audit/2026-06-01-report.md
```
Expected: fichier présent, lignes de tableau nombreuses.

---

## Task 6: Vérification de l'audit + commit

- [ ] **Step 1: Gates qualité**

- Couverture = 100% (Task 5 Step 1 : missing=0).
- 100% des `pass` ont une preuve non vide ; 100% des `fail/partial` ont `fix` + fichier.
```bash
python3 - <<'PY'
import json, glob
bad=0
for f in glob.glob('.audit/findings-*.json'):
    for x in json.load(open(f))['findings']:
        if x['verdict']=='pass' and not x.get('evidence'): bad+=1; print('PASS sans preuve:', x['slug'])
        if x['verdict'] in ('fail','partial') and not x.get('fix'): bad+=1; print('FAIL sans fix:', x['slug'])
print('violations:', bad)
PY
```
Expected: `violations: 0`.

- [ ] **Step 2: Spot-check manuel (3 findings)**

Re-vérifier à la main 1 `required`, 1 `recommended`, 1 `avoid` contre le code/runtime réel. Corriger le rapport si un verdict est faux.

- [ ] **Step 3: Commit du rapport (branche `feature/seo-ai-spec-audit`)**

> `.audit/` est gitignored (artefacts jetables) — on ne committe QUE le rapport.
```bash
git add docs/seo-ai-audit/2026-06-01-report.md .gitignore
git commit -F - <<'EOF'
docs(seo): add specification.website conformance audit report

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
EOF
```
(`-F -` contourne proprement le hook conventional-commit qui mal-parse les `-m` multiples.)

- [ ] **Step 4: Handoff**

Le **plan d'attaque** du rapport (P0/P1/P2) devient l'entrée d'un nouveau cycle writing-plans → implémentation des correctifs via le flow git standard (branches `fix/<slug>` depuis `dev`). Ne PAS appliquer les correctifs dans cet audit.

---

## Self-Review (effectué)

- **Couverture spec** : design §pipeline → Tasks 2-5 ; §map catégorie → Task 4 Step 1 ; §schéma finding → Task 4 ; §priorisation → Task 5 Step 3 ; §vérification audit → Task 6. ✓
- **Placeholders** : commandes et structure JSON concrètes ; pas de "TODO". Les slugs exacts sont volontairement tirés du MCP à l'exécution (Task 2) — c'est la source de vérité, pas un placeholder. ✓
- **Cohérence types** : schéma de finding identique entre Task 4 (prompt agent), Task 5 (merge) et Task 6 (gates) — clés `slug/status/verdict/evidence/gap/fix/effort`. ✓
- **Dégradation** : Lighthouse indispo → `na`, pas de faux `pass` (Task 3 Step 6, Task 5). ✓
