From 9cd7b51bb897f19ea7981fbbce7fec8ee3d0b6d1 Mon Sep 17 00:00:00 2001 From: Bastien Chanot Date: Thu, 16 Jul 2026 16:25:16 +0200 Subject: [PATCH] =?UTF-8?q?fix(seo,geo):=20dogfood=20on=20zenquality.fr=20?= =?UTF-8?q?=E2=80=94=20two=20process=20anomalies?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Surfaced by pointing /harden at zenquality.fr from the claude-config CWD. A1 — no CWD/target coherence guard (systemic: /seo, /geo, /harden all lack it; grep confirms). A URL is supplied, the agent greps whatever CWD it landed in, nobody checks they are the same site. Demonstrated live: from claude-config, /harden would curl zenquality.fr while grepping claude-config, then score "Config hardening" on a codebase that is not the site. The live half looks right, the code half is fiction, and the report reads as authoritative. Fixed in both agents' STEP 2 rather than the 3 dispatchers: the agent does the grepping, so the guard binds whoever calls — same principle as I3. /harden inherits it free. A2 — seo-analyzer had zero origin-vs-edge awareness while geo-analyzer has the full CDN/WAF-override check (geo-analyzer.md:246-261). seo-analyzer does the infra detection AND is reused by /harden for its whole config-hardening axis (20/100). On zenquality — Apache origin behind a Scaleway nginx front — repo .htaccess + `server: nginx` invites the wrong call "nginx serves this, .htaccess is dead". I made that exact inference myself before reading the file. Rule added at STEP 2 infra detection: `server:` names the edge, not the origin; live-but-not-in-repo = "set upstream", never "missing". Verified: live probe of zenquality.fr (read-only, nothing written to the client repo); make test 35 GREEN / 0 RED. --- agents/geo-analyzer.md | 10 ++++++++++ agents/seo-analyzer.md | 28 ++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/agents/geo-analyzer.md b/agents/geo-analyzer.md index 6e14ead..307e918 100644 --- a/agents/geo-analyzer.md +++ b/agents/geo-analyzer.md @@ -141,6 +141,16 @@ If called standalone via `/geo`, gather: ## STEP 2 — DETECT CONTEXT `[both]` +**FIRST — the CWD must BE the audited site.** You grep the current working +directory; no dispatcher checks that it matches the target domain. If a URL +was supplied and the CWD shows no web project at all (no `package.json` / +`composer.json` / `index.html` / `*.astro` / `*.php` / `.htaccess`), or its +signals contradict the domain, STOP and report: +`CWD/TARGET MISMATCH — is not 's repo. Re-run from it, or +confirm live-only audit (LOCAL findings will be N/A).` +Never grep one codebase while curling another: the live half looks right, +the code half is fiction, and the report reads as authoritative. + ```bash # Framework (reuse detection from seo-analyzer if available) ls package.json composer.json Gemfile Cargo.toml go.mod 2>/dev/null diff --git a/agents/seo-analyzer.md b/agents/seo-analyzer.md index 43c36bb..b5ef9bc 100644 --- a/agents/seo-analyzer.md +++ b/agents/seo-analyzer.md @@ -81,6 +81,17 @@ hreflang, infer from detected URL structures. ## STEP 2 — DETECT TECHNICAL CONTEXT `[both]` +**FIRST — the CWD must BE the audited site.** You grep the current working +directory; no dispatcher checks that it matches TARGET_URL. If a URL was +supplied and the CWD shows no web project at all (no `package.json` / +`composer.json` / `index.html` / `*.astro` / `*.php` / `.htaccess`), or its +signals contradict the domain, STOP and report: +`CWD/TARGET MISMATCH — is not 's repo. Re-run from it, or +confirm live-only audit (LOCAL findings will be N/A).` +Never grep one codebase while curling another: the live half looks right, +the code half is fiction, and the report reads as authoritative. `/harden` +inherits this agent for its config axis, so the mismatch propagates there. + ### Framework & rendering ```bash @@ -148,6 +159,23 @@ RECOMMENDATION : KEEP & CONFIGURE plugin | INSTALL (P0 quick win) | M ### Infrastructure signals +**Origin vs edge — never infer the stack from `server:`.** That header names +whatever answered: usually the EDGE (Cloudflare, Scaleway/OVH front, CDN, +load balancer), not the origin. Apache behind an nginx front is a standard +topology — TLS terminated upstream, the origin sees plain HTTP plus +`X-Forwarded-Proto`. +- Repo `.htaccess` + `server: nginx` = NOT drift, NOT dead config. Do not + flag it, do not propose migrating it. +- Never move headers into an `nginx.conf` absent from the repo. Server-side + config you cannot read is a §14 gap, not a finding. +- A header present live but in no repo config = "set upstream", never + "missing". + +`/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. + ```bash # Server / hosting ls .htaccess nginx.conf netlify.toml vercel.json wrangler.toml 2>/dev/null