feat(agents): de-prescribe seo-analyzer for Opus 5 (C1 P2)

Choreography → when-guidance under the audience×mode-range invariant
(plan §4b Q3). Census 71/0 + model-routing 133/0 + seo-data 221/0 green
throughout; contract surface (§2a/2b) byte-identical; 1528→1503 lines.

- self-output verification: ':970 run it twice' → deterministic-engine
  integrity guard (conf#8); ':1217 do not proceed' → single-shot-scoped
  (conf#1); grouping sanity-check → when-guidance detector (rob#8)
- vestigial pre-BDR-061 'Transparency' line deleted; §15 ownership
  folded into 'Dispatcher verifies'
- dedup (inspection-corrected: most annex 'twins' are distinct
  obligations — kept): only true same-range dups removed ('Handoff to
  dispatcher' ≈ sentinel note; 'Landing page rule' block ≈ payload
  instance + RULES line)
- completeness checklist reshaped to routing map, rows verbatim (rob#3)
- caps softened: 'P0 rule' MUST/ALWAYS → plain content rules (CMS
  plugin-first folded with STEP 2 twin, corr#3); First-action/ordering
  emphasis dropped; C1a + sampling essays compressed (rules + LRN
  citations kept); WebSearch → drifting-externals when-guidance (rob#6)
- FROZEN untouched: guard-first orderings :287, denominator-before-
  sampling :550, R2 refuse, COVERAGE obligations, all STEP headers
- deltas: 'P0 rule' 2→0, ALWAYS 1→0, MUST 5→4; NEVER 9→9 (class-B
  named bans, kept by design LRN-105)
This commit is contained in:
Bastien Chanot
2026-08-02 01:30:02 +02:00
parent 9681b468e1
commit adafa350da
+54 -79
View File
@@ -58,8 +58,8 @@ STEP 1-2 business/tech context is consumed by all later steps).
## STEP 0 — AUDIT DEPTH
**First action.** If a parent skill (`/seo` dispatcher) passed depth
in $ARGUMENTS, use it. Otherwise:
If a parent skill (`/seo` dispatcher) passed depth in $ARGUMENTS, use
it. Otherwise:
```
SEO AUDIT DEPTH — choose one:
@@ -141,11 +141,10 @@ Record rendering: **SSR / SSG / SPA / hybrid / ISR**.
### CMS detection + SEO plugin presence (plugin-first strategy)
Before proposing any manual edit, detect if the site runs on a CMS
and whether a SEO plugin is already handling the heavy lifting. If a
CMS is detected WITHOUT a SEO plugin, the highest-priority quick win
is to install the appropriate plugin — editing theme files manually
is a last resort and creates maintenance debt.
Detect whether the site runs on a CMS and whether a SEO plugin is
already handling the heavy lifting; record the signals. The
plugin-first ranking policy (CMS without plugin → installation is the
top quick win) lives in STEP 10.
```bash
# WordPress signals
@@ -206,8 +205,7 @@ topology — TLS terminated upstream, the origin sees plain HTTP plus
`/harden` reuses this agent for its entire config-hardening axis, so a wrong
topology call scores a client's server config against a file that never ran.
geo-analyzer STEP 4 already carries the matching CDN/WAF-override check —
keep the two consistent.
(The same CDN/WAF-override check lives in geo-analyzer STEP 4.)
```bash
# Server / hosting
@@ -505,7 +503,7 @@ Fetch rendered HTML. Extract and analyze:
## STEP 5 — ON-PAGE AUDIT `[both]`
### Rendering gate — run this BEFORE anything else in STEP 5 (R2)
### Rendering gate (R2) — it gates every on-page check below
```bash
bash ~/.claude/lib/seo-data/fetch.sh rendercheck --url "https://$DOMAIN/"
@@ -599,9 +597,9 @@ doorway-page risk — the exact thing the 30/70 rule exists to catch — is
invisible. Group by shared parent AND by shared slug prefix; if ≥3 URLs share
a prefix of 2+ hyphen tokens, that is a family whatever the depth.
Sanity-check the grouping before trusting it: a site whose sitemap yields
almost as many families as URLs has probably defeated your heuristic, not
proved it has no templates.
A sitemap that yields almost as many families as URLs has probably
defeated the heuristic, not proved the site has no templates — say so
instead of trusting the grouping.
**Sample by finding class, because the classes need opposite samples:**
@@ -611,10 +609,9 @@ proved it has no templates.
| **Duplication / 30-70 / cannibalisation** | **≥3 from the LARGEST family** | invisible with one page each. You cannot tell whether 25 city pages are 70% unique by reading one of them. |
| Per-page content (title/description length, H1 wording) | spread across families + GSC position 4-10 quick wins | these vary per page even from one template. |
"One per template" is right for code and **wrong for the 30/70 rule** — a
rule this spec mandates in §9. Sampling one page per family makes that check
structurally impossible, so take the third page of the biggest family even
though it is "the same template".
The split is deliberate: one-per-family alone makes the §9 30/70 check
structurally impossible — hence ≥3 pages from the biggest family, even
though they share a template.
An un-sampled family is an un-audited family. Name the ones you skipped.
@@ -658,16 +655,11 @@ mapfile -t FEXCL < <(bash ~/.claude/lib/source-scope.sh findargs)
find . "${FEXCL[@]}" -type f \( -iname "*.jpg" -o -iname "*.jpeg" -o -iname "*.png" -o -iname "*.gif" \) -printf "%s %p\n" 2>/dev/null | sort -rn | head -20
```
**Why the guard, and why `find` specifically (C1a).** `grep` and `find`
disagree about this repo and you use both. Claude Code routes `grep` through
ugrep with `--ignore-files`, so it honours `.gitignore` and never descends
into a gitignored `dist/`. `find` honours nothing. Measured on a real Astro
repo: this command returned **92 images, 45 of them under `dist/`** — every
asset twice, source and generated copy, byte-identical. So "top 20 by size"
was ~10 real images dressed as 20, and a batch-C item
(`cwebp -q 80 <img> -o <img>.webp`) could target `dist/og-image.png`, whose
`.webp` the dispatcher's own `npm run build` then erases. The fix lands,
verification passes, nothing survives.
**Why the guard, and why `find` specifically (C1a).** Claude Code routes
`grep` through ugrep with `--ignore-files` (honours `.gitignore`); `find`
honours nothing. Measured on a real Astro repo: without the guard this
command returned 92 images, 45 under `dist/` — and a batch-C item built
on that targets an artifact the dispatcher's own `npm run build` erases.
`FEXCL` MUST be consumed as a quoted array. `find . $FEXCL …` lets the shell
glob `*/dist/*` against the CWD and hand the matches to find as search paths
@@ -967,8 +959,9 @@ disagree, and `/client-handover` gates on 17/20.
**N/A is not a zero** and the engine will not let it behave like one.
- `status: "error"` → malformed findings. Fix them; never fall back to
eyeballing a number.
- Run it twice on the same file before publishing. If the output moved, your
findings moved, and that is the thing to explain.
- The engine is deterministic: if you modified the findings JSON after
scoring, re-run and explain the move — a shifted score means shifted
findings, never engine noise.
**Technical axis note:** CWV scored on CrUX field data (75th percentile,
real users, from STEP 4) when available; otherwise lab PageSpeed
@@ -1144,22 +1137,19 @@ For each:
- Expected impact (high / medium / low)
- AUTO (bundled in STEP 12, applied by the dispatcher) or USER (in SEO.md §11, with automation options)
AUTO items are a commitment, not a suggestion.
**CMS plugin first**: a CMS detected in STEP 2 without a SEO plugin
makes plugin installation the top quick win —
RankMath/Yoast/SEOPress (WordPress), Yoast SEO (Drupal), SEO Suite
Ultimate (Magento), Plug in SEO (Shopify) deliver meta + sitemap +
OG + breadcrumbs + JSON-LD in ~15 min of admin UI, where hand-editing
theme files first creates duplication, conflicts, and maintenance
debt. See `~/.claude/agents/resources/automation-catalog.md` CMS
plugins section for the exact install path per CMS.
**P0 rule — CMS plugin first**: if STEP 2 detected a CMS without a
SEO plugin, the FIRST quick win MUST be plugin installation. Reason:
installing RankMath/Yoast/SEOPress (WordPress), Yoast SEO (Drupal),
SEO Suite Ultimate (Magento), Plug in SEO (Shopify) takes ~15 min
via admin UI and delivers meta + sitemap + OG + breadcrumbs + JSON-LD
in one shot. Editing theme files by hand before this creates
duplication, conflicts, and maintenance debt. See
`~/.claude/agents/resources/automation-catalog.md` CMS plugins
section for the exact install path per CMS.
**P0 rule — Bing Webmaster Tools**: on FULL audit, ALWAYS emit
"Submit site to Bing Webmaster Tools" as a user action — ChatGPT
Search uses the Bing index, so this is also a GEO signal. See
automation-catalog.md for IndexNow + Bing.
**Bing Webmaster Tools** (FULL audits): emit "Submit site to Bing
Webmaster Tools" as a user action — ChatGPT Search uses the Bing
index, so this is also a GEO signal. See automation-catalog.md for
IndexNow + Bing.
### Medium term (1-3 months)
City/service pages (30/70 rule: 30% shared, 70% unique per city),
@@ -1214,7 +1204,8 @@ BATCH F — USER ACTIONS (N items, documented in SEO.md §11 with automation cat
...
```
Do not proceed to STEP 12 until this plan is printed.
Single-shot runs (no MODE line) print this plan before STEP 12
serializes it; `MODE: judge` simply ends here.
---
@@ -1306,18 +1297,19 @@ as the last line of the bundle — the dispatcher keys its apply step on it.
Do NOT run any post-fix verification (build/lint, NAP consistency); the
dispatcher does that after it applies. Your job ends at the sentinel.
### Bundle completeness checklist (did every finding reach the bundle?)
### Finding-class → tier routing (complete map: every finding lands in
exactly one tier; §11 mirrors USER ACTIONS)
- [ ] Meta/title/OG/canonical → AUTO (hotfixer)
- [ ] JSON-LD LocalBusiness/Organization → AUTO (hotfixer/feater) — detailed GEO schema → geo-analyzer
- [ ] Image alt/dimensions → AUTO (hotfixer); compression → AUTO (bash) or §11 if tools absent
- [ ] robots.txt / sitemap.xml → AUTO (hotfixer) — AI-bot directives → geo-analyzer
- [ ] .htaccess security headers, image/video sitemap, hreflang → AUTO (feater)
- [ ] Legal pages, CMP, footer links → AUTO (feater)
- [ ] Heading hierarchy, noindex on technical pages → AUTO (hotfixer)
- [ ] Unverifiable aggregateRating removal → AUTO (hotfixer); stock-photo testimonials → GATED (E)
- [ ] Structural / new pages → GATED (D)
- [ ] Video transcripts, GMB, directories → USER ACTIONS (§11)
- Meta/title/OG/canonical → AUTO (hotfixer)
- JSON-LD LocalBusiness/Organization → AUTO (hotfixer/feater) — detailed GEO schema → geo-analyzer
- Image alt/dimensions → AUTO (hotfixer); compression → AUTO (bash) or §11 if tools absent
- robots.txt / sitemap.xml → AUTO (hotfixer) — AI-bot directives → geo-analyzer
- .htaccess security headers, image/video sitemap, hreflang → AUTO (feater)
- Legal pages, CMP, footer links → AUTO (feater)
- Heading hierarchy, noindex on technical pages → AUTO (hotfixer)
- Unverifiable aggregateRating removal → AUTO (hotfixer); stock-photo testimonials → GATED (E)
- Structural / new pages → GATED (D)
- Video transcripts, GMB, directories → USER ACTIONS (§11)
### Framework-specific notes
@@ -1339,23 +1331,6 @@ Carry the relevant note into each bundle item so the applier honors it:
- **Ghost** — Native SEO strong (meta + OG + JSON-LD out of box). Usually no plugin needed; handle gaps via `default.hbs` edits.
- **Wix / Squarespace / Webflow (hosted CMS)** — No theme file access. ALL SEO changes happen in the admin UI: meta, alt, sitemap, redirects, JSON-LD (partial). Agent emits detailed USER action list per panel to touch — cannot auto-apply anything.
### Landing page rule
Zero visible change on landing/homepage except:
- Meta tags (invisible)
- Footer links (discreet)
- JSON-LD (invisible)
- Image fixes: compression, alt, dimensions (invisible or quasi)
Anything else → batch D (confirmation).
### Handoff to dispatcher
Post-fix verification (build/lint, NAP consistency across JSON-LD /
visible / GMB, revert-on-break) and the §15 change log are the
DISPATCHER's responsibility, AFTER it applies the bundle at L1. You
emitted the bundle terminated by the sentinel — stop here.
---
## STEP 13 — OUTPUT `[both]`
@@ -1519,10 +1494,10 @@ PROCHAINE ETAPE : <highest-priority>
### Process
- **Every user action lists automation.** Mandatory from
`~/.claude/agents/resources/automation-catalog.md`.
- **WebSearch on FULL** to validate tool landscape + cross-check
competitor state before emitting.
- **WebSearch on FULL when naming drifting externals** — tool
landscapes and competitor state shift; cross-check before a
recommendation names them.
- **Iterative SEO.md.** Preserve Historique section.
- **Transparency.** Every automated change logged with file, change,
reason.
- **Dispatcher verifies.** Build/lint pass + revert-on-break happen in
the dispatcher after it applies the bundle — never in this agent.
- **Dispatcher verifies.** Build/lint pass, revert-on-break and the §15
change log happen in the dispatcher after it applies the bundle —
never in this agent.