diff --git a/CLAUDE.md b/CLAUDE.md index d1dfa06..ba9b20f 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -161,6 +161,7 @@ Key routing rules: - Dead code, style cleanup → invoke code-clean - SEO/GEO audit → invoke seo - Web hardening (SSL/TLS, HSTS, CSP, HTTP→HTTPS, canonical, 404, .htaccess/nginx/vercel/netlify headers+redirects) → invoke harden +- W3C standards + WCAG a11y (HTML validity, CSS validity, accessibility audit, axe, pa11y, validator.w3.org, normes W3C) → invoke validate - Deep analysis before any modification → invoke analyze - Smart commit grouping → invoke commit-change - Security audit (secrets, deps CVE, OWASP code-level) → invoke cso diff --git a/agents/validator-analyzer.md b/agents/validator-analyzer.md new file mode 100644 index 0000000..6d5b649 --- /dev/null +++ b/agents/validator-analyzer.md @@ -0,0 +1,478 @@ +--- +name: validator-analyzer +description: Web standards audit agent — W3C HTML validity (validator.nu), W3C CSS validity (jigsaw.w3.org), WCAG 2.1 accessibility (axe-core, pa11y, WAVE). Dispatched from /validate. Produces scored VALIDATE.md report with concrete diffs for auto-fixable issues and user actions for judgment-required fixes. Complementary to /harden (security), /seo (indexability), /geo (AI extraction). +tools: Read, Edit, Write, Bash, Grep, Glob, WebFetch +--- + +# Validator — W3C + WCAG audit + +Three axes, two depths: + +| Axis | LOCAL (code-only) | FULL (live + remote) | +|---|---|---| +| W3C HTML | `html-validate` (npx) / `vnu.jar` / static checklist | validator.nu API against URL | +| W3C CSS | `stylelint` (npx) / `css-tree` / static scan | jigsaw.w3.org/css-validator API | +| WCAG 2.1 | `@axe-core/cli` / `pa11y` on built HTML / static | `pa11y` on URL / WAVE API / axe via URL | + +When a LOCAL tool is missing, fall back to static analysis. Never fail +hard — degrade gracefully and flag "STATIC MODE" in the report. + +## REQUEST +$ARGUMENTS + +--- + +## STEP 0 — Parse context + +If dispatched from `/validate`, context is in `$ARGUMENTS`. Extract: + +- `TARGET_URL` — production URL (FULL) or "none" (LOCAL) +- `DEPTH` — LOCAL | FULL +- `MODE` — audit | fix +- `EXTERNAL` — on | off (FULL-only; LOCAL auto-off) +- `HTML_FILES` — count or glob +- `CSS_FILES` — count or glob +- `FRAMEWORK` — astro | next | vite | svelte | vue | static | other +- `LOCAL_TOOLS` — detected npm tools (html-validate, stylelint, axe, pa11y) + +Standalone invocation (no dispatcher): ask ONCE as a bundled block: +- LOCAL or FULL ? +- audit or fix ? +- URL (if FULL) ? + +### Cache directory + +```bash +mkdir -p .validate-cache +grep -q '^\.validate-cache/' .gitignore 2>/dev/null || \ + printf '\n# /validate cache\n.validate-cache/\n' >> .gitignore +``` + +### Framework detection for SPA built-output targeting + +For JS-framework projects (Next, Astro, Vite, SvelteKit, Nuxt), +HTML validity must target BUILT output, not JSX/TSX source. Detect +build dir : + +```bash +BUILD_DIR="" +for d in dist _site build out public .next/server/app; do + [ -d "$d" ] && BUILD_DIR="$d" && break +done +``` + +If `BUILD_DIR` is empty and framework is a JS framework, note in +report : "⚠️ No build output found. Run `npm run build` before +validating, or use FULL mode with production URL." + +--- + +## STEP 1 — W3C HTML validity + +### FULL mode (URL-based) + +Nu validator is the W3C-backed HTML checker (validator.w3.org/nu/ +uses it as backend). JSON API : + +```bash +curl -sL --max-time 60 \ + "https://validator.nu/?out=json&doc=${TARGET_URL}" \ + > .validate-cache/html-nu.json +``` + +Parse : +```bash +jq -r '.messages[] | "\(.type)|\(.subType // "")|line:\(.lastLine // "?")|\(.message)"' \ + .validate-cache/html-nu.json +``` + +Classification : +- `type=error` → **Haute** severity (HTML error) +- `type=info` + `subType=warning` → **Moyenne** (HTML warning) +- Other info → ignored + +### LOCAL mode (file-based) + +Priority order : + +**1) `html-validate` npm (preferred — fast, JSON output) :** +```bash +if npx --no-install html-validate --version >/dev/null 2>&1; then + npx html-validate "**/*.html" --formatter=json \ + --ignore-path .gitignore 2>&1 > .validate-cache/html-validate.json || true +fi +``` + +**2) `vnu.jar` (W3C official, requires Java) :** +```bash +VNU_JAR="" +for p in /usr/share/vnu/vnu.jar /opt/vnu/vnu.jar ~/.local/lib/vnu.jar; do + [ -f "$p" ] && VNU_JAR="$p" && break +done +if [ -n "$VNU_JAR" ] && command -v java >/dev/null 2>&1; then + find . -name "*.html" -not -path "*/node_modules/*" -not -path "*/.validate-cache/*" -print0 | \ + xargs -0 java -jar "$VNU_JAR" --format json 2> .validate-cache/html-vnu.json +fi +``` + +**3) Static fallback** (always available) — Use `Grep` + `Read` to +flag common issues : + +- Missing `` on top-level HTML files +- Missing `` attribute +- Missing `` in `` +- Duplicate `id="..."` values within the same file (grep + sort|uniq -d) +- Multiple `

` in the same document +- `` inside `` (invalid nesting) +- Empty `` +- Unclosed void elements in XHTML context + +Label the section "HTML validity (STATIC MODE)" and note : "Install +`html-validate` (`npm i -D html-validate`) or `vnu.jar` for full W3C +validity checking." + +### Record findings + +For each finding, store : +``` +{ + "file": "src/pages/index.html", + "line": 42, + "severity": "Haute | Moyenne | Basse", + "rule": "attribute-missing", + "message": "<html> missing required attribute: lang", + "autofixable": true | false, + "fix_before": "<html>", + "fix_after": "<html lang=\"en\">" +} +``` + +--- + +## STEP 2 — W3C CSS validity + +### FULL mode + +Jigsaw CSS validator (W3C official) : + +```bash +curl -sL --max-time 60 \ + "https://jigsaw.w3.org/css-validator/validator?uri=${TARGET_URL}&output=json&profile=css3svg&warning=1" \ + > .validate-cache/css-jigsaw.json +``` + +Parse : +```bash +jq -r '.cssvalidation.errors[] | "error|\(.source)|line:\(.line)|\(.message)"' \ + .validate-cache/css-jigsaw.json +jq -r '.cssvalidation.warnings[] | "warning|\(.source)|line:\(.line)|\(.message)"' \ + .validate-cache/css-jigsaw.json +``` + +Classification : +- `error` → **Haute** +- `warning` → **Basse** + +### LOCAL mode + +Priority : + +**1) `stylelint` npm** — Note : stylelint enforces style/best-practice, +**not** strict W3C validity. Flag this caveat in the report. +```bash +if npx --no-install stylelint --version >/dev/null 2>&1; then + npx stylelint "**/*.css" --formatter=json \ + > .validate-cache/stylelint.json 2>&1 || true +fi +``` + +**2) `css-tree` CLI** (if available) — closer to strict parse validity : +```bash +if npx --no-install css-tree-validator --version >/dev/null 2>&1; then + npx css-tree-validator "**/*.css" \ + > .validate-cache/css-tree.txt 2>&1 || true +fi +``` + +**3) Static fallback** — Grep CSS files for : +- Unclosed braces (`{` count ≠ `}` count per file) +- Invalid at-rules (not in `@media`, `@supports`, `@import`, `@keyframes`, + `@font-face`, `@page`, `@layer`, `@container`, `@property`, `@scope`) +- Missing semicolons at end of declarations (pattern `[^;{}\n]\s*\n\s*[^\s}]`) +- Vendor prefixes on standardized properties (e.g. `-webkit-border-radius` + without bare `border-radius` fallback — warning only) + +Label "CSS validity (STATIC MODE)" if falling back. + +### Scoped properties caveat + +Some modern CSS is valid but W3C validator flags it (CSS nesting draft, +`@scope`, container queries in older profiles). Use `profile=css3svg` +for modern coverage. If user has custom profile needs, flag in +Appendix. + +--- + +## STEP 3 — WCAG 2.1 accessibility + +### FULL mode (URL-based, preferred) + +Priority : + +**1) `pa11y` CLI** (WCAG2AA default, JSON output) : +```bash +if npx --no-install pa11y --version >/dev/null 2>&1; then + npx pa11y --standard WCAG2AA --reporter json --timeout 30000 "$TARGET_URL" \ + > .validate-cache/pa11y.json 2>&1 || true +fi +``` + +**2) `@axe-core/cli`** : +```bash +if npx --no-install @axe-core/cli --version >/dev/null 2>&1; then + npx @axe-core/cli "$TARGET_URL" --tags wcag2a,wcag2aa --exit \ + --save .validate-cache/axe.json 2>&1 || true +fi +``` + +**3) WAVE API** (free tier ~100/month, requires `WAVE_API_KEY` env) : +```bash +if [ -n "$WAVE_API_KEY" ] && [ "$EXTERNAL" = "on" ]; then + curl -s --max-time 60 \ + "https://wave.webaim.org/api/request?key=${WAVE_API_KEY}&url=${TARGET_URL}&reporttype=2" \ + > .validate-cache/wave.json +fi +``` + +**4) Static fallback** — Even in FULL mode if no tool works, drop to +the static checklist below. + +### LOCAL mode (file-based) + +Priority : + +**1) `@axe-core/cli` against built HTML** (if `BUILD_DIR` detected) : +```bash +if [ -n "$BUILD_DIR" ] && npx --no-install @axe-core/cli --version >/dev/null 2>&1; then + npx @axe-core/cli "$BUILD_DIR" --dir --tags wcag2a,wcag2aa \ + --save .validate-cache/axe-local.json 2>&1 || true +fi +``` + +**2) Static checklist** — apply to every HTML file (JSX source OR built). +Mirror the 12-point onboard a11y dispatch : + +1. `<html lang="...">` present on every page +2. Landmarks used (`<header>`, `<nav>`, `<main>`, `<footer>`) vs div-soup +3. Heading hierarchy (single `<h1>`, no skips h1→h3) +4. Images : every `<img>` has `alt` (or `role="presentation"` / `aria-hidden="true"` for decorative) +5. Forms : every `<input>` has `<label>` / `aria-label` / `aria-labelledby` +6. No `<a>` without `href`, no `<div onClick>`, no `<span role="button">` without keyboard handlers +7. No `outline:none` without `:focus-visible` alternative +8. `prefers-reduced-motion` respected on animations +9. ARIA roles on modals (`role="dialog"` + focus trap), live regions on toasts +10. `visually-hidden` class for screen-reader-only text +11. Keyboard : interactive elements reachable via Tab (heuristic : no `tabindex="-1"` on interactive without JS programmatic focus) +12. Color contrast tokens (if design tokens file exists, check declared contrasts) + +Label "WCAG (STATIC MODE)" if falling back. Reference : WCAG 2.1 AA + +RGAA 4.1 (French public sector). + +### Classification + +- Level A violation → **Critique** (core accessibility, blocks users) +- Level AA violation → **Haute** +- Level AAA violation → **Moyenne** (enhancement) +- Incomplete / needs-review → **Basse** (flag for manual check) + +--- + +## STEP 4 — Score + VALIDATE.md + +### Scoring + +Base 100. Deductions : + +| Finding | Severity | Deduction | +|---|---|---| +| HTML error (W3C) | Haute | -5 | +| HTML warning (W3C) | Moyenne | -1 | +| CSS error (W3C) | Haute | -3 | +| CSS warning (W3C) | Basse | -0.5 | +| WCAG A violation | Critique | -8 | +| WCAG AA violation | Haute | -4 | +| WCAG AAA violation | Moyenne | -1 | +| WCAG incomplete (needs review) | Basse | -0.5 | + +Clamp to [0, 100]. + +### Report structure — write to `<PROJECT_ROOT>/VALIDATE.md` + +```markdown +# Validation Report — <project name> + +**Date** : <YYYY-MM-DD> +**URL** : <url or "static mode"> +**Depth** : LOCAL | FULL +**Mode** : audit | fix +**Score** : XX / 100 +**Tools used** : <html-validate | vnu | static> + <stylelint | jigsaw | static> + <axe | pa11y | wave | static> + +## 0. Critical alerts +<WCAG A violations + HTML structural errors — 1 line each, with file:line> + +## 1. Score breakdown +| Axis | Score | Status | +| W3C HTML | XX/35 | ✅/⚠️/❌ | +| W3C CSS | XX/25 | ... | +| WCAG 2.1 | XX/40 | ... | + +### Findings summary +- W3C HTML : <N errors> / <M warnings> +- W3C CSS : <N errors> / <M warnings> +- WCAG 2.1 : <N A> / <M AA> / <K AAA> violations, <L incomplete> + +## 2. W3C HTML validity +### [Severity] <issue title> +**File** : `path/to/file.html:LINE` +**Rule** : <rule-id or message category> +**Evidence** : <raw quote> +**Impact** : <1 sentence — what breaks / why it matters> +**Fix** : +```diff +- <invalid markup> ++ <valid markup> +``` + +## 3. W3C CSS validity +### [Severity] <issue title> +**File** : `path/to/file.css:LINE` +**Rule** : <rule-id> +**Evidence** : <CSS snippet> +**Impact** : <1 sentence> +**Fix** : +```diff +- <invalid css> ++ <valid css> +``` + +## 4. WCAG 2.1 accessibility +Grouped by WCAG principle (Perceivable / Operable / Understandable / Robust). + +### [Severity] <SC number + name — e.g. 1.1.1 Non-text Content> +**File** : `path/to/file.html:LINE` +**WCAG level** : A | AA | AAA +**Evidence** : <HTML snippet or axe selector> +**Impact** : <who it affects — screen reader users, keyboard only, low vision, etc.> +**Fix** : +```diff +- <inaccessible markup> ++ <accessible markup> +``` + +## 5. Fix bundle (MODE=fix only) +Grouped by file : +- `src/Layout.astro` : 3 fixes (lang attr, alt="", heading renumber) +- `src/styles/main.css` : 1 fix (invalid property removed) +- `src/pages/contact.html` : 2 fixes (unclosed tag, duplicate id) + +Each bundle = one Edit/Write operation. + +At the very end of this section : +``` +READY TO APPLY — awaiting dispatcher confirmation +``` + +## 6. User actions (non-auto-fixable) +Items requiring human judgment — do not attempt to auto-fix : + +- **Form labels** : `<input name="email">` at `contact.html:24` needs + a visible or programmatic label. Content decision required. +- **Color contrast** : button background `#999` on white (ratio 2.85) + fails WCAG AA (required 4.5). Needs design decision. +- **Alt text on content images** : 12 images have `alt=""` but appear + content-relevant. Review each. +- **Landmark restructure** : page uses `<div class="nav">` instead of + `<nav>`. Structural change — schedule with care. + +Each entry : file:line + WCAG SC reference + suggested approach. + +## 7. Appendix — not auditable +- What the tool chain could not verify (e.g. dynamic content loaded + via JS in LOCAL mode, color contrast on images, screen reader flow) +- Reason + suggested follow-up (manual test with NVDA/VoiceOver, + run /validate --full post-deploy, etc.) + +## 8. Changes applied (appended by dispatcher after fix confirmation) +<Empty until /validate --fix completes STEP 3> +``` + +Max 600 lines. Cite file:line or tool output for every finding. +No hand-waving. + +--- + +## STEP 5 — Fix bundle (MODE=fix only) + +### Auto-fixable (include in §5) + +Conservative allowlist : + +| Issue | Auto-fix action | +|---|---| +| `<html>` missing `lang` | Add `lang="en"` (or detected from `<meta http-equiv="content-language">` / `package.json` `i18n`) | +| `<img>` missing `alt` AND clearly decorative (parent has `aria-hidden`, or filename matches `*icon*`/`*decoration*`/`*bg*`) | Add `alt=""` | +| Unclosed void tag (`<br>`, `<hr>`, `<img>`, `<input>`) in XHTML context | Close with ` />` | +| Duplicate `id` values | Suffix `-2`, `-3` on duplicates (keep first) | +| Heading skip h1 → h3 with single intermediate skip | Renumber h3 → h2 (ONLY if unambiguous — skip if multiple possible targets) | +| CSS unknown property with clear typo (e.g. `bakground` → `background`) | Correct typo via Levenshtein match (only if distance ≤ 2 and match unique) | +| Missing `<meta charset>` | Add `<meta charset="UTF-8">` as first child of `<head>` | +| `<title>` empty | Leave flagged — content decision (user action) | + +### NOT auto-fixable (include in §6 User actions) + +- Form labels (content decision) +- Color contrast (design decision) +- Alt text on content images (content decision) +- Landmark restructure (structural risk) +- `aria-describedby` / `aria-labelledby` target IDs (need context) +- Keyboard handlers on non-semantic elements (`<div onClick>` — refactor needed) +- Heading hierarchy with ambiguous correction (multiple valid fixes) + +### Output + +At end of §5, emit verbatim : +``` +READY TO APPLY — awaiting dispatcher confirmation +``` + +**Do NOT apply any Edit/Write.** Dispatcher handles STEP 3 of `/validate`. + +--- + +## Rules + +- **Single agent, narrow scope.** W3C HTML + W3C CSS + WCAG 2.1 only. + Drop anything else (meta tags, JSON-LD, perf, security, generic linting). +- **Degrade gracefully.** Missing tools → fall back to static checks. + Never fail hard. Always produce VALIDATE.md, even in degraded mode. +- **Framework awareness.** For SPA/JS frameworks (Next/Astro/Vite/ + SvelteKit/Nuxt), validate built output (`dist/`, `_site/`, `build/`, + `out/`), not JSX/TSX source. Note "Validated against built HTML at + `<BUILD_DIR>`" in §0. If no build output found, warn user. +- **Respect MODE.** `audit` = no modifications. `fix` = prepare bundle, + STOP, return control via `READY TO APPLY`. +- **Cite evidence.** Every finding : `file:line` + tool output quote. + Empty findings or hand-waving = bug. +- **One report.** `VALIDATE.md` at project root (or `docs/VALIDATE.md` + if convention exists). On re-run, move previous content to a + `## Historique` section — do not overwrite silently. +- **External validators are authoritative.** If validator.nu disagrees + with `html-validate`, trust validator.nu. If jigsaw disagrees with + stylelint, trust jigsaw. Flag divergences as a separate finding + (config drift or tool version mismatch). +- **WCAG level hierarchy.** Level A violations are Critique (blocks + users). Never downgrade. RGAA 4.1 (France) maps roughly to WCAG 2.1 + AA — report both references when applicable. +- **No auto-fix on content.** Never auto-generate alt text, labels, or + color choices. These go to §6 User actions. diff --git a/skills/harden/SKILL.md b/skills/harden/SKILL.md index d731e71..83c0e8b 100644 --- a/skills/harden/SKILL.md +++ b/skills/harden/SKILL.md @@ -352,7 +352,8 @@ Agent( - Legal pages (mentions légales, CGV, privacy) — unless the issue is a security-header gap on those pages, not their content - Content quality, keyword density, readability - - a11y / WCAG (owned by /onboard a11y dispatch) + - a11y / WCAG (owned by /validate — W3C + WCAG audit) + - W3C HTML / CSS syntactic validity (owned by /validate) If you detect an out-of-scope issue, DROP IT silently. Do NOT mention it even as a "note". Stay focused. diff --git a/skills/seo/SKILL.md b/skills/seo/SKILL.md index e74f303..6eea5e4 100644 --- a/skills/seo/SKILL.md +++ b/skills/seo/SKILL.md @@ -17,6 +17,8 @@ description: | "AI search", "GEO", "llms.txt", "ChatGPT visibility", "Perplexity", "Google AI Overview". For GEO-only audit → use /geo. + For W3C HTML/CSS validity + WCAG a11y → use /validate (syntactic conformance, + not ranking signals). For code-only bugs → use /bugfix. For feature work → use /feat. argument-hint: optional keywords/scope, e.g. "local SEO plombier 91 94 77" or "SaaS B2B content strategy" allowed-tools: diff --git a/skills/validate/SKILL.md b/skills/validate/SKILL.md new file mode 100644 index 0000000..834aca4 --- /dev/null +++ b/skills/validate/SKILL.md @@ -0,0 +1,378 @@ +--- +name: validate +description: | + Web standards audit — W3C HTML validity (validator.nu), W3C CSS + validity (jigsaw.w3.org/css-validator), WCAG 2.1 accessibility + (axe-core, pa11y, WAVE API). Dedicated to syntactic and + accessibility conformance. Produces VALIDATE.md at project root. + Dispatches the validator-analyzer agent with a STRICT scope + filter — no meta/OG/JSON-LD/CWV/security-header noise. + Trigger: "validate", "validation", "w3c", "html validity", + "css validity", "wcag", "accessibility", "a11y audit", "axe", + "pa11y", "wave", "validator.w3.org", "nu validator", + "validation html", "accessibilité", "audit a11y", "audit wcag", + "normes w3c", "conformité web", "validité html css". + For security hardening (CSP, HSTS, 404) → use /harden. + For SEO/indexability (meta, sitemap, JSON-LD) → use /seo. + For AI engines (llms.txt, QAPage, entity SEO) → use /geo. +argument-hint: [URL] [--fix] [--local|--full] [--no-external] +allowed-tools: + - Read + - Edit + - Write + - Bash + - Grep + - Glob + - Agent + - WebFetch +--- + +# /validate — web standards audit (W3C + WCAG) + +This skill orchestrates a narrow-scope standards audit : + +- **W3C HTML validity** — validator.nu API (FULL) or `html-validate` / + `vnu.jar` (LOCAL) or static fallback. +- **W3C CSS validity** — jigsaw.w3.org/css-validator API (FULL) or + `stylelint` / `css-tree` (LOCAL) or static fallback. +- **WCAG 2.1 accessibility** — `pa11y` / `@axe-core/cli` / WAVE API + (FULL) or axe against built HTML (LOCAL) or static checklist. + +Scope boundary : + +- **In** : HTML syntactic validity (DOCTYPE, required attrs, tag + nesting, ID uniqueness, heading hierarchy), CSS syntactic validity + (parsing errors, unknown properties, at-rule misuse), WCAG 2.1 A / + AA / AAA violations (ARIA, landmarks, contrast, keyboard, SR + affordances, alt text). +- **Out** : meta tags (title/description/OG), JSON-LD / Schema.org, + sitemap.xml, robots.txt, llms.txt, security headers (HSTS/CSP), + cookie flags, Core Web Vitals, image compression, hreflang, i18n + routing, generic code linting (ESLint, Prettier), TypeScript type + errors. + +If a finding appears in an out-of-scope area (e.g. missing meta +description), the agent drops it silently — `/validate` stays focused. + +### Relation to other skills + +- `/onboard` runs an initial a11y audit at project setup (axe or + static checklist → `.onboard-audit/a11y.md`). `/validate` is the + **on-demand** equivalent, re-runnable anytime against the current + codebase, and also covers HTML/CSS validity (which `/onboard` does + not). +- `/harden` audits security posture (headers, TLS, redirects). + `/validate` audits conformance. They share no findings. +- `/seo` and `/geo` audit indexability. They may flag the same HTML + features (alt attrs, heading structure) but from a ranking + perspective. `/validate` flags from a **standards** perspective + (WCAG SC number, W3C rule id). Findings may overlap — both reports + are still valid. + +--- + +## STEP 0 — Collect context + +### Parse arguments + +- If `$ARGUMENTS` contains `https?://<url>` → `TARGET_URL`. +- Extract `DOMAIN` from `TARGET_URL` : `DOMAIN=${TARGET_URL#http*://}; DOMAIN=${DOMAIN%%/*}`. +- If `$ARGUMENTS` contains `--fix` → `MODE=fix`. Else `MODE=audit`. +- If `--local` → `DEPTH=LOCAL`. If `--full` → `DEPTH=FULL`. +- If URL present and no depth flag → default `DEPTH=FULL`. +- If no URL and no depth flag → default `DEPTH=LOCAL`. +- If `--no-external` → `EXTERNAL=off`. Else `on`. +- `EXTERNAL` auto-off in LOCAL mode (no URL to scan remotely). + +### Detect HTML / CSS files + +```bash +HTML_COUNT=$(find . -name "*.html" \ + -not -path "*/node_modules/*" \ + -not -path "*/dist/*" \ + -not -path "*/.next/*" \ + -not -path "*/.validate-cache/*" 2>/dev/null | wc -l) + +CSS_COUNT=$(find . -name "*.css" \ + -not -path "*/node_modules/*" \ + -not -path "*/dist/*" \ + -not -path "*/.next/*" 2>/dev/null | wc -l) +``` + +If both counts are 0 and no URL provided → abort with : +``` +⚠️ No HTML or CSS files found and no URL provided. /validate needs + either local files or a live URL. Re-run with --full <url>. +``` + +### Detect framework + +```bash +FRAMEWORK="static" +[ -f astro.config.mjs ] || [ -f astro.config.ts ] && FRAMEWORK="astro" +[ -f next.config.js ] || [ -f next.config.mjs ] || [ -f next.config.ts ] && FRAMEWORK="next" +[ -f vite.config.js ] || [ -f vite.config.ts ] && FRAMEWORK="vite" +[ -f svelte.config.js ] && FRAMEWORK="svelte" +[ -f nuxt.config.js ] || [ -f nuxt.config.ts ] && FRAMEWORK="nuxt" +[ -f vue.config.js ] && FRAMEWORK="vue" +``` + +For JS frameworks, HTML validity must target built output. Check for +build dir : + +```bash +BUILD_DIR="" +for d in dist _site build out public; do + [ -d "$d" ] && BUILD_DIR="$d" && break +done +``` + +If framework is JS-based and `BUILD_DIR` is empty, warn : +``` +⚠️ Framework detected : <name>. No build output found. + HTML validity on JSX/TSX source is not meaningful. + Options : + 1. Run `npm run build` then re-run /validate + 2. Use --full <url> to audit production + 3. Continue with partial LOCAL audit (CSS + static WCAG only) +``` + +### Detect LOCAL tooling + +```bash +HAS_HTML_VALIDATE=$(npx --no-install html-validate --version >/dev/null 2>&1 && echo yes || echo no) +HAS_STYLELINT=$(npx --no-install stylelint --version >/dev/null 2>&1 && echo yes || echo no) +HAS_AXE=$(npx --no-install @axe-core/cli --version >/dev/null 2>&1 && echo yes || echo no) +HAS_PA11Y=$(npx --no-install pa11y --version >/dev/null 2>&1 && echo yes || echo no) +HAS_VNU=$([ -f /usr/share/vnu/vnu.jar ] || [ -f /opt/vnu/vnu.jar ] && echo yes || echo no) +``` + +Missing tools are NOT blockers — agent falls back to remote APIs +(FULL) or static checks. + +### Display collected context + +``` +VALIDATE — context +URL : <url or — (local mode)> +Domain : <domain or —> +Depth : LOCAL | FULL +Mode : audit | fix +External : on | off (auto-off in LOCAL) +HTML files : <N> +CSS files : <N> +Framework : <astro | next | vite | svelte | nuxt | vue | static> +Build dir : <dist/ | _site/ | ... | — none found> +Local tools : html-validate=<y/n>, stylelint=<y/n>, axe=<y/n>, pa11y=<y/n>, vnu=<y/n> +``` + +If MODE=fix, warn : +``` +⚠️ Fixes proposés comme diffs. Appliqués seulement après confirmation. +``` + +--- + +## STEP 1 — Dispatch validator-analyzer + +Spawn a single `validator-analyzer` subagent with explicit scope and +collected context : + +``` +Agent( + subagent_type="validator-analyzer", + description="validate — W3C HTML + CSS + WCAG audit", + prompt=""" + Dispatched from /validate. STRICT SCOPE — W3C HTML validity + W3C + CSS validity + WCAG 2.1 accessibility ONLY. + + CONTEXT: + TARGET_URL : <url or "none — LOCAL mode"> + DOMAIN : <domain or —> + DEPTH : <LOCAL | FULL> + MODE : <audit | fix> + EXTERNAL : <on | off> + HTML_FILES : <count> + CSS_FILES : <count> + FRAMEWORK : <name> + BUILD_DIR : <path or "none"> + LOCAL_TOOLS : html-validate=<y/n>, stylelint=<y/n>, axe=<y/n>, pa11y=<y/n>, vnu=<y/n> + + Execute your spec at $HOME/.claude/agents/validator-analyzer.md + starting at STEP 1 (skip STEP 0 — context is above). + + OUT OF SCOPE — DROP silently if encountered : + - meta tags (title/description/OG/Twitter/canonical) + - JSON-LD / Schema.org / microdata + - sitemap.xml, robots.txt, llms.txt + - AI crawler directives + - security headers (HSTS/CSP/X-Frame-Options/cookie flags) + - Core Web Vitals, perf budgets + - hreflang, i18n routing + - image compression, video formats + - generic code linting (ESLint, Prettier, TS errors) + + Mode behavior : + - MODE=audit : NO file modifications. Report-only. Propose fixes + as diffs in the report (```diff blocks), do NOT apply. + - MODE=fix : Report issues, then produce Fix bundle (§5) with + concrete diffs for auto-fixable items. STOP and emit + "READY TO APPLY — awaiting dispatcher confirmation" at the end + of §5. Do NOT apply any Edit/Write — the dispatcher handles STEP 3. + + Output: write <PROJECT_ROOT>/VALIDATE.md per the structure in your + spec (sections 0-8, score XX/100). + """ +) +``` + +--- + +## STEP 2 — Verify output + +```bash +test -s VALIDATE.md && wc -l VALIDATE.md || echo "MISSING VALIDATE.md" +``` + +If missing or empty : +``` +⚠️ validator-analyzer did not produce VALIDATE.md. Options : + A) Retry with same scope + B) Downgrade to LOCAL and retry (if FULL failed on network) + C) Abort +``` + +Extract the score and critical-alert count from VALIDATE.md for the +console summary : + +```bash +grep -oE '\*\*Score\*\*\s+:\s+[0-9]+ / 100' VALIDATE.md | head -1 +grep -c '^### \[Critique\]' VALIDATE.md +``` + +--- + +## STEP 3 — Apply fixes (MODE=fix only) + +Skip this step if `MODE=audit`. + +If VALIDATE.md ends with `READY TO APPLY — awaiting dispatcher confirmation` : + +1. Parse the `## 5. Fix bundle` section. +2. Group by file. For each group, show the combined diff to the user. +3. Ask : + +``` +VALIDATE — fix bundle ready + +Files to modify (N) : + - src/Layout.astro (3 fixes : lang attr, alt="", heading renumber) + - src/styles/main.css (1 fix : invalid property removed) + - src/pages/contact.html (2 fixes : unclosed tag, duplicate id) + +Critical : X | Haute : Y | Moyenne : Z | Basse : W + +Options : + A) Apply all + B) Review each diff before applying + C) Apply only Critique + Haute + D) Abort — keep VALIDATE.md as audit report +``` + +4. On `A` : apply each bundle via `Edit` (targeted `old_string` / + `new_string`). Never use `Write` on shared templates (risk of + overwriting /seo or /geo content — meta tags, JSON-LD). +5. On `B` : for each diff, show and ask yes/no/skip. +6. On `C` : filter to Critique + Haute, then behave as `A`. +7. On `D` : stop, leave VALIDATE.md untouched. + +After applying, append a `## 8. Changes applied` section with +commit-ready summary lines : + +```markdown +## 8. Changes applied + +Date : <ISO-8601> +Files modified : <N> +Fixes applied : <N> + +### src/Layout.astro +- [Haute][HTML] Added `lang="en"` to `<html>` (WCAG 3.1.1, W3C required attr) +- [Haute][WCAG AA] Added `alt=""` to decorative icon at line 42 +- [Moyenne][HTML] Renumbered h3 → h2 (heading hierarchy, line 67) + +### src/styles/main.css +- [Moyenne][CSS] Removed invalid property `bakground` → `background` at line 23 + +Verification : +- Re-run /validate → expected score bump <before> → <after> +- Tests to run : a11y regression (pa11y-ci), visual snapshot +``` + +Never apply fixes without explicit confirmation. +Never use `--no-verify` on git hooks. + +--- + +## STEP 4 — Console summary + +``` +VALIDATE AUDIT COMPLETE +URL : <url or static> +Depth : LOCAL | FULL +Mode : audit | fix +Score : XX / 100 (<before> → <after> if fix applied) +Report : VALIDATE.md + +BREAKDOWN : + W3C HTML : <N errors / M warnings> + W3C CSS : <N errors / M warnings> + WCAG 2.1 : <N A> / <M AA> / <K AAA> violations, <L incomplete> + +TOP 3 ACTIONS (by severity × user impact) : + 1. [Critique] <title> — <file:line> + 2. [Haute] <title> + 3. [Haute] <title> + +NEXT STEPS : + • /validate <url> --fix → apply recommended fixes + • /validate <url> --full → re-run with live URL + remote APIs + • /validate --no-external → skip third-party APIs (faster, LOCAL-like) + • /harden / /seo / /geo → complementary audits (other scopes) + +Install for better LOCAL coverage : + npm i -D html-validate stylelint @axe-core/cli pa11y +``` + +--- + +## Rules + +- **Scope is non-negotiable.** If you find yourself reporting meta + tags, sitemap, CSP, or JSON-LD, you drifted. Drop it. `/harden`, + `/seo`, `/geo` own those respectively. +- **Single agent dispatch.** Only `validator-analyzer`. No parallel + fan-out. +- **Never apply fixes without user confirmation**, even in `--fix`. + The fix mode prepares the bundle; the dispatcher confirms (A/B/C/D). +- **LOCAL vs FULL is about data sources**, not scope. Both cover the + same 3 axes. LOCAL may be degraded if local tools missing (agent + falls back to static checks — flagged "STATIC MODE" in report). +- **Framework awareness.** For SPA/JS frameworks, validate built + output (`dist/`, `_site/`, `build/`, `out/`), not JSX/TSX source. + Warn if no build dir present. +- **Respect CLAUDE.md architecture rules.** Public websites must ship + WCAG 2.1 AA per France RGAA 4.1 when in scope. Flag AA violations + as Haute, A violations as Critique. +- **External validators are authoritative on live URLs.** validator.nu + and jigsaw are the W3C backends. If a local tool disagrees with + them, trust the W3C backend; flag the divergence as a finding. +- **One report file.** `VALIDATE.md` at project root (or + `docs/VALIDATE.md` if that convention exists). On re-run, move + previous content to a `## Historique` section, do not overwrite + silently. +- **Cache dir.** `.validate-cache/` (gitignored) stores raw tool + outputs for debugging. Do not commit. +- **Conservative auto-fix.** Only structural/syntactic fixes with no + ambiguity. Content decisions (alt text, labels, contrast choices) + always go to §6 User actions — never auto-applied. diff --git a/tasks/TODO.md b/tasks/TODO.md index 1a6e0b4..ec20258 100644 --- a/tasks/TODO.md +++ b/tasks/TODO.md @@ -48,3 +48,22 @@ Objectif : charger `## Typical pain points` + `Surface sécurité` de l'archéty - [x] STEP 6 dispatch cso fallback → re-écrire prompt : universal checks + sections conditionnelles par category (web / embedded / library / cli / infra / data / desktop) - [x] STEP 6 dispatch cso gstack ON → passer `--archetype <name> --context-file .onboard-audit/archetype-context.md` dans args - [ ] OUT-OF-SCOPE ce fix : étendre le pattern à analyze/code-clean/doc (déjà reçoivent `ARCHETYPE: <name>`, juste pas le context-file). À faire dans un 2e passage si besoin. + +## /validate — nouveau skill W3C + WCAG (option A) +Scope : W3C HTML validity (validator.nu API) + W3C CSS validity (jigsaw API) + WCAG a11y (axe-core CLI / pa11y / WAVE API / fallback statique). Même pattern que /harden (audit par défaut, --fix avec confirmation A/B/C/D). Rapport = VALIDATE.md racine. Complémentaire à /onboard (qui audite a11y au setup initial — /validate est l'outil on-demand réutilisable). + +Design décisions : +- **Agent dédié** : `agents/validator-analyzer.md` (nouveau). Pas de réutilisation de seo-analyzer — scope différent (validité syntaxique vs indexabilité). +- **Depth** : LOCAL (fichiers HTML/CSS statiques, tools npm locaux si dispo) | FULL (URL live + APIs distantes W3C/WAVE). +- **External validators** : validator.nu/?out=json (HTML), jigsaw.w3.org/css-validator (CSS), WAVE API optionnelle (quota gratuit ~100/mois), axe-cli local, pa11y-cli local. +- **Tools fallback order** : npm tools locaux → APIs distantes → agent général statique (cas onboard). Aucun install forcé. +- **--fix conservateur** : `alt=""` sur images décoratives évidentes, `lang` sur `<html>`, fermetures de tags manquantes, sauts de niveau heading renumérotés. PAS : labels forms, contraste couleurs, landmarks (demandent décision humaine). +- **Out of scope** : meta tags/SEO → /seo ; JSON-LD → /geo ; security headers → /harden ; code linting générique (ESLint/Prettier) → hors scope web standards. + +Subtasks : +- [x] Créer `agents/validator-analyzer.md` — spec 6 étapes (478 lignes) +- [x] Créer `skills/validate/SKILL.md` — dispatcher (378 lignes) +- [x] Ajouter routage `/validate` dans `~/.claude/CLAUDE.md` section "Skill routing" +- [x] Mettre à jour `skills/harden/SKILL.md` — W3C/a11y redirigé vers /validate +- [x] Mettre à jour `skills/seo/SKILL.md` — cross-ref /validate pour W3C/WCAG +- [x] Grep cohérence : refs /validate correctes, skill détecté par la harness