git:20261006.ff44a3b to git:20261006.b4403b0

72 added, 336 removed. Audit A to A.

---
name: wp-audit-geo-standards
- description: GEO and AI-agent-readiness reference — the ORA/is-agentic check catalog, applicability by site type, AI crawler allowlist, llms.txt and well-known specs, GEO citability rubric, and WordPress implementation templates. Use when auditing or fixing how a site reads to AI search and agents (the wp-audit-geo and wp-agentic-surfaces agents), or when writing llms.txt, robots.txt AI-crawler rules or /.well-known agent files.
+ description: GEO and AI-agent-readiness reference — the ORA and is-agentic scoring model, the GEO-D, GEO-A, GEO-U and GEO-P check catalog, applicability by site type (content, local, merchant, catalog store, SaaS), the AI crawler allowlist for robots.txt and the Content-Signal header, the dynamic llms.txt, ARD catalog (ard.json), agent-skills index, markdown negotiation and other surfaces inc/agentic.php serves, the bin/geo-scan.sh live verifier, and a citability rubric for writing copy that AI engines quote. Use when running /wp-audit --geo, explaining why is-agentic grades a site, fixing GEO findings with wp-agentic-surfaces, choosing which AI crawlers robots.txt allows, or writing section copy for ChatGPT and Perplexity to cite. Not for Rank Math titles, meta descriptions, sitemap or schema configuration (wp-audit-seo-standards), and not for accessibility fixes, which GEO-U01 to U05 only mirror.
user-invocable: false
---
# GEO & Agent-Readiness Standards
- Scored by **ORA**, surfaced at [is-agentic.com](https://is-agentic.com). Four layers,
- 125 checks. Full live catalog: `GET https://ora.ai/api/checks`.
+ Scored by **ORA**, surfaced at [is-agentic.com](https://is-agentic.com), in four layers.
+ The live check catalog is `GET https://ora.ai/api/checks`; every count and weight below is a
+ snapshot of it, so re-fetch it before quoting a number as current.
- This skill informs the audit (`agents/wp-audit-geo.md`) and the fix
- (`agents/wp-agentic-surfaces.md`). It never runs commands on its own.
+ This skill informs the audit (`${CLAUDE_PLUGIN_ROOT}/agents/wp-audit-geo.md`) and the fix
+ (`${CLAUDE_PLUGIN_ROOT}/agents/wp-agentic-surfaces.md`), which holds the executable version
+ of every surface. It never runs commands on its own. Terms used throughout: a **crawler** is
+ an AI user agent named in `robots.txt`; the **allowlist** is which crawlers `robots.txt`
+ admits; a **surface** is a URL the theme serves for agents (`/llms.txt`, `/.well-known/…`);
+ the **check catalog** is ORA's list of checks, and the **ARD catalog** is `ard.json`.
+ ## Reference files
+
+ - [references/check-catalog.md](references/check-catalog.md) — every GEO code, the ORA check
+ ids it maps to and whether the theme can fix it. Read when mapping an ORA id to a code,
+ tabulating a code, or deciding whether a finding is fixable or advisory.
+ - [references/surface-templates.md](references/surface-templates.md) — what each surface must
+ contain: the minimum robots body, `llms.txt`, `ard.json`, the agent-skills index,
+ `pricing.md`, markdown negotiation, `Link:` headers, the agent-friendly 404, JSON-LD
+ breadth, trust anchors, `llms-full.txt` and `auth.md`. Read when building or checking a
+ surface.
+ - [references/citability.md](references/citability.md) — the citability rubric and a
+ weak-to-strong rewrite. Read when writing or tightening page copy (`/wp-section`,
+ `/wp-seed`); no audit code scores it.
+
---
## 1. Scoring model
| Layer | Weight | Checks |
|---|---|---|
| Discovery | 20 | 16 |
| Access | 30 | 41 |
| Usability | 40 | 62 |
| Payments | 10 | 6 |
| **Total** | **100** | **125** |
Each check belongs to one of three tiers:
| Tier | Count | Pool |
|---|---|---|
| `required` | 29 checks | share an **80**-point Essential pool |
| `recommended` | 76 checks | share **20** points |
| `emerging` | 20 checks | bonus-only, capped at +5 |
**Non-applicable checks are excluded, never failed.** A brochure site is not
penalized for having no API, OAuth, MCP, or payment surface — those checks are
reported `N/A` exactly as ORA excludes them.
Grades: **A+** 95+ · **A** 86+ · **B** 70+ · **C** 48+ · **D** 28+ · **F** <28.
The weighted layer score is `Σ(maxScore of passed applicable checks) / Σ(maxScore of
applicable checks)`, re-weighted against the layers that apply. The Essential pool is
scored before the bonus pool: a `required` failure costs more than a `recommended`
failure, and an `emerging` pass can only lift the grade, never save it.
---
## 2. Applicability by site type
Site type is **detected, not assumed**, from **positive signals** — the project's
`.claude/CLAUDE.md` (`industry`), active plugins, an OpenAPI/public-API signal, the page
inventory and templates. A registered REST namespace is **not** a signal: Rank Math,
Yoast, SEOPress and CF7 all register one, so scanning `rest_get_server()` marks an
ordinary content site as SaaS. Every check not implied by the detected type is reported
`N/A`.
| Site type | Detection | Layers that apply |
|---|---|---|
| content / publisher / service | default when no positive signal matches | Discovery + Access + GUI-Usability |
| **local business** | `industry` = local/business **and** a non-empty `business_address` | + LocalBusiness schema, NAP, reviews |
| **merchant** | `site.commerce` `woocommerce` from `/wp-audit` Step 2.3; standalone, `class_exists('WooCommerce')` / `$WP plugin is-active woocommerce` | + Payments, `pricing.md`, Product schema |
| **SaaS** / public API | an OpenAPI spec or a deliberate public API surface recorded in `.claude/CLAUDE.md` | + OpenAPI / api-catalog / MCP / OAuth |
The auditor runs only the applicable subset and prints the exclusion rationale for
every `N/A` layer. A WordPress site with WooCommerce active but products disabled
still counts as `merchant` for detection purposes; the payment-protocol checks stay
- advisory either way.
+ advisory either way, because no WooCommerce payment gateway speaks an agent payment
+ protocol (§8).
A catalog store is a merchant that deliberately takes no payment. When `/wp-audit` Step 2.3
records `site.store_tier` = `catalog` (read from the `store` block of `.wp-create.json`),
the payment-protocol codes GEO-P01 to GEO-P05 are `N/A ("catalog: nothing purchasable")`:
an agent payment protocol has nothing to pay for. `unknown` is not `catalog` — audit them.
Read the recorded tier; never infer it from whether a checkout page happens to exist.
---
- ## 3. Check catalog — GEO codes
-
- Prefix `GEO-<layer><nn>`; layer letter D/A/U/P. Each code maps to one or more ORA
- check ids and is the unit later agents reference and tabulate. Codes carry the full
- mapping here; the audit/fixable subset is what the fixer can actually change.
-
- Wildcard groups in the design spec §6 are expanded below to the concrete ids in the
- live catalog. `yes` = the theme/host can fix it. `advisory` = detected and reported,
- not fixed (off-site, network- or third-party-dependent). `*` = only when the site
- type implies it.
-
- ### Discovery — GEO-D
-
- | Code | ORA check ids | Fixable |
- |---|---|---|
- | GEO-D01 | `ard-catalog`, `ai-catalog-published`, `ard-entries-valid` | yes — `/.well-known/ard.json` + `ai-catalog.json` alias |
- | GEO-D02 | `robots-ai-policy-quality`, `robots-agent-user-policy` | yes — robots policy + `Content-Signal` |
- | GEO-D03 | `ard-trust-manifest` | yes — trust manifest in the ARD catalog |
- | GEO-D04 | `agent-rules-repo`, `agent-plugins-repo` | yes — `/agents.md`, the AGENTS.md document served by `inc/agentic.php` |
- | GEO-D05 | `brand-search-accuracy` | advisory — measured via ORA / DataForSEO |
- | GEO-D06 | `agentic-search-specific`, `agentic-search-usecase` | advisory — share of voice |
- | GEO-D07 | `wikipedia-presence` | advisory — off-site |
- | GEO-D08 | `registry-branding`, `skills-sh-listed`, `chatgpt-app-listed`, `mcp-registry-listed`, `npm-sdk-package` | advisory — off-site |
-
- ### Access — GEO-A
-
- | Code | ORA check ids | Fixable |
- |---|---|---|
- | GEO-A01 | `content-no-js` | yes — raw-HTML content ≥500 chars, first heading `H1`, sequential, ≥5% ratio |
- | GEO-A02 | `bot-detection` | yes — AI UA allowlist in WAF/robots |
- | GEO-A03 | `redirect-hygiene` | yes — real 301/302, no meta-refresh or JS redirect |
- | GEO-A04 | `agent-friendly-404` | yes — real 404 status + short markdown body |
- | GEO-A05 | `docs-auth-gate` | yes — keep public pages ungated |
- | GEO-A06 | `metadata-completeness` | yes — canonical + `lang` + `og:image` + `og:type` together |
- | GEO-A07 | `json-ld` | yes, when no SEO plugin owns the graph (§6.8) — identity JSON-LD |
- | GEO-A08 | `json-ld-entity-linking` | yes, when no SEO plugin owns the graph (§6.8) — `sameAs` |
- | GEO-A09 | `org-schema-completeness` | yes, when no SEO plugin owns the graph (§6.8) — `contactPoint` + `address` |
- | GEO-A10 | `schema-type-breadth` | yes, when no SEO plugin owns the graph (§6.8) — FAQPage/Service/Product/AggregateRating/BreadcrumbList |
- | GEO-A11 | `trust-anchors` | yes — `/about`, `/contact`, `/privacy` each ≥500 chars |
- | GEO-A12 | `sitemap`, `sitemap-lastmod` | yes — Rank Math `lastmod` on |
- | GEO-A13 | `llms-txt-exists` | yes — dynamic endpoint |
- | GEO-A14 | `llms-txt-formatting` | yes |
- | GEO-A15 | `llms-txt-links-resolve` | yes |
- | GEO-A16 | `modular-llms-txt` | yes — per-area `llms.txt` |
- | GEO-A17 | `agent-instruction` | yes — "When to use" block |
- | GEO-A18 | `page-token-budget` | yes — trim oversized pages |
- | GEO-A19 | `markdown-negotiation`, `markdown-negotiation-vary`, `markdown-url-fallback`, `markdown-frontmatter`, `code-fence-validity`, `markdown-link-alternate` | yes — `Accept: text/markdown` + `Vary` |
- | GEO-A20 | `link-headers-discovery` | yes — RFC 8288 `Link:` |
- | GEO-A21 | `agent-discovery-file`, `agent-skills-index-v2` | yes — `/.well-known/agent-skills/index.json` |
- | GEO-A22 * | `openapi-spec`, `public-api-docs`, `developer-portal`, `api-catalog-rfc9727` | SaaS/API only |
- | GEO-A23 | `agent-crawler-reachability` | yes |
- | GEO-A24 * | `pricing-info`, `pricing-md` | merchant/SaaS |
- | GEO-A25 † | — no ORA id | yes — every referenced `@id` resolves inside the `@graph` |
- | GEO-A26 † | — no ORA id | yes — no physical root file shadowing a theme rewrite |
- | GEO-A27 † | — no ORA id | no — fixed at the CDN, not in the theme |
- | GEO-A28 † | — no ORA id | yes — advertised URLs resolve and agree with the sitemap |
-
- † GEO-A25 through GEO-A28 are **plugin-added**: the ORA catalog has no check that resolves a schema
- reference, so a graph whose `publisher` points at an `@id` no node declares passes
- `json-ld`, `json-ld-entity-linking` and `org-schema-completeness` alike. Report it
- outside the ORA score — the score must stay reproducible against the published catalog.
- The same holds for the three serving-layer and surface-agreement codes: ORA scores what a
- URL returns, so it cannot see that the returning file is a physical one shadowing the
- theme, that the canonical path only answers through a redirect, or that a surface
- advertises pages the site does not publish.
-
- ### Usability — GEO-U
-
- | Code | ORA check ids | Fixable |
- |---|---|---|
- | GEO-U01 | `ax-document-structure` | yes — `main`, landmarks, single H1, sequential |
- | GEO-U02 | `ax-native-controls` | yes |
- | GEO-U03 | `ax-accessible-names` | yes |
- | GEO-U04 | `ax-form-labeling` | yes |
- | GEO-U05 | `ax-tree-injection-safe` | yes |
- | GEO-U06 * | `json-error-responses`, `api-error-model` | API only |
- | GEO-U07 * | `mcp-server`, `mcp-server-identity`, `mcp-tool-listing`, `mcp-tool-naming`, `mcp-tool-descriptions`, `mcp-param-schemas`, `mcp-tool-annotations`, `mcp-resource-listing`, `mcp-resource-quality`, `mcp-auth-mechanism`, `mcp-oauth-metadata`, `mcp-pkce-s256`, `mcp-error-handling`, `mcp-transport-modern`, `mcp-server-card`, `mcp-multi-surface-coverage` | MCP only |
- | GEO-U08 * | `oauth-support`, `oauth-protected-resource`, `scoped-permissions`, `auth-md-exists`, `auth-md-structure`, `auth-md-walkthrough-simulation`, `agent-auth-discovery-metadata`, `agent-auth-www-authenticate`, `agent-auth-endpoints-reachable` | API/MCP only |
- | GEO-U09 * | `onboarding-friction`, `sandbox-environment` | SaaS only |
- | GEO-U10 | `cli-tool`, `webmcp`, `a2ui-support`, `nlweb-schema-feeds`, `nlweb-ask`, `nlweb-streaming` | advisory / emerging |
-
- ### Payments — GEO-P (merchant only, `N/A` on a catalog store)
-
- | Code | ORA check ids | Fixable |
- |---|---|---|
- | GEO-P01 | `acp-support`, `acp-delegate-payment` | advisory |
- | GEO-P02 | `ucp-support` | advisory |
- | GEO-P03 | `mpp-support` (the Machine Payments Protocol; MCP payment rides on the MCP surface checks in GEO-U07) | advisory |
- | GEO-P04 | `x402-support` | advisory |
- | GEO-P05 | `ap2-support` | advisory |
+ ## 3. Check catalog
- Payment protocols are largely advisory for WooCommerce today (see §8 Ceilings). The
- fixer reports the recommendation and does not fabricate protocol support.
+ Codes are `GEO-<layer><nn>`, layer letter D, A, U or P. Each maps to one or more ORA check
+ ids and is the unit the agents tabulate and report; the full table, with what the theme can
+ fix, is [references/check-catalog.md](references/check-catalog.md). GEO-A25 to GEO-A28 are
+ the plugin's own: ORA has no check for them, so they are reported outside the ORA score.
---
## 4. AI crawler allowlist
`robots.txt` must name each AI crawler explicitly — a bare `User-agent: *` does not
satisfy `robots-agent-user-policy`. The default posture is **ALLOW** for the retrieval
- and training agents below; confirm the commercial intent with the site owner before
- changing it.
+ and training crawlers below.
| Crawler | Operator | Policy |
|---|---|---|
| `GPTBot` | OpenAI (training + crawl) | ALLOW |
| `OAI-SearchBot` | OpenAI Search | ALLOW |
| `ChatGPT-User` | OpenAI live browsing | ALLOW |
| `ClaudeBot` | Anthropic (training + crawl) | ALLOW |
| `PerplexityBot` | Perplexity | ALLOW |
| `Google-Extended` | Google Gemini training | ALLOW |
| `GoogleOther` | Google research crawl | ALLOW |
| `Applebot-Extended` | Apple Intelligence | ALLOW |
| `Amazonbot` | Amazon | ALLOW |
| `FacebookBot` | Meta AI | ALLOW |
| `CCBot` | Common Crawl | not named — falls under `User-agent: *`; `Disallow` it only when the owner does not want the site in the public corpus |
| `anthropic-ai` | Anthropic, legacy token | not named — when it is, give it `ClaudeBot`'s policy |
| `Bytespider` | ByteDance / TikTok | BLOCK for Western markets |
- Minimum robots body — every ALLOW row above, then the BLOCK row:
-
- ```
- User-agent: GPTBot
- Allow: /
-
- User-agent: OAI-SearchBot
- Allow: /
-
- User-agent: ChatGPT-User
- Allow: /
-
- User-agent: ClaudeBot
- Allow: /
-
- User-agent: PerplexityBot
- Allow: /
-
- User-agent: Google-Extended
- Allow: /
-
- User-agent: GoogleOther
- Allow: /
-
- User-agent: Applebot-Extended
- Allow: /
-
- User-agent: Amazonbot
- Allow: /
-
- User-agent: FacebookBot
- Allow: /
+ The minimum robots body is every ALLOW row, then the BLOCK row, after the classic
+ `User-agent: *` block — written out in
+ [references/surface-templates.md](references/surface-templates.md).
- User-agent: Bytespider
- Disallow: /
- ```
+ **The training posture is the owner's decision, and a deliberate one stands.** An existing
+ `Disallow` for a named crawler, or an `ai-train=no` signal, is the site owner's answer, not
+ a defect: the auditor reports it as a deliberate block (consistent or not with the signal,
+ below), and the fixer asks before changing it — it never rewrites a deliberate block back to
+ the default. The default applies only where the site states no posture at all.
Send the policy signal as an HTTP response header, and never as a line of `robots.txt`:
```
Content-Signal: ai-train=yes, search=yes, ai-retrieval=yes
```
No robots.txt grammar defines a `Content-Signal` directive, so a validator that lints the
file — Lighthouse among them — reports the whole `robots.txt` invalid over that one line.
The file may document the signal in a `#` comment; the header is what carries it.
`Content-Signal` declares the site's AI usage posture and **must match the robots
allowlist** — a signal that contradicts the rules fails both `robots-ai-policy-quality` and
`robots-agent-user-policy`. The allowlist above permits training-capable crawlers (`GPTBot`,
`ClaudeBot`, `Google-Extended`, `Applebot-Extended`), so the matching signal is
`ai-train=yes`. A site that wants to refuse training must also `Disallow` those crawlers and
set `ai-train=no`; `search=yes, ai-retrieval=yes` keeps it discoverable in AI answers either
way.
---
- ## 5. GEO citability rubric
-
- Citability is a property of the **copy**, not the markup. It scores how likely a
- generative engine is to lift a passage verbatim. Weights:
-
- | Component | Weight | What it means |
- |---|---|---|
- | Answer-block quality | 30% | A direct 1–2 sentence answer opens the section ("X is…") |
- | Self-containment | 25% | The passage reads correctly with no surrounding context |
- | Structural readability | 20% | Question-based H2s, short paragraphs, tables for 3+ comparisons |
- | Statistical density | 15% | Named numbers, units, dates sourced to first-party data |
- | Uniqueness | 10% | Original data or framing, not a restatement of the consensus |
-
- Concrete rules:
-
- - **Optimal extractable passage length: 134-167 words.** Below that the engine has too
- little to quote; above it gets truncated mid-argument.
- - Open every section with a 1–2 sentence answer before any elaboration. Do not bury the
- answer under a definition parade.
- - Phrase H2s as questions where the content answers one (`What does X cost?`).
- - Use a table whenever three or more things are compared; prose comparisons are not
- extractable as a unit.
- - Name sources and dates inline (`per the 2025 WordPress project survey…`).
- - Prefer first-party data — measured numbers we own — over adjectives.
- - One idea per passage; a section that answers two questions gets split.
-
- The rubric is for **generation**: `/wp-section` and `/wp-seed` authors apply it when
- writing copy. No GEO code scores it, so the auditor reports nothing against it.
-
- ---
-
- ## 6. Surface templates
-
- The fixer writes the theme's `inc/agentic.php`, which owns every surface below. All are
- applicability-gated; a content site does not emit API or payment surfaces.
-
- ### 6.1 Dynamic `llms.txt`
-
- Route `/llms.txt` (and `/llms-full.txt`) through WordPress, not a static file — a
- static file goes stale. Structure:
-
- ```
- # {Site Name}
-
- > {One-line site description}
-
- ## Key Facts
- - {Identity, location, hours, what the site sells/offers}
- - {Trust anchors: founded, credentials, first-party numbers}
-
- ## Pages
- - [Page Title](url): excerpt or first 20 words
-
- ## Posts
- - [Post Title](url): excerpt
-
- ## When to use
- - {Agent-facing guidance: what this site is authoritative for, and when to reach it}
-
- ## Contact
- - Website: {home_url}
- ```
-
- Per-area modular files (`/services/llms.txt`, `/docs/llms.txt`, …) satisfy
- `modular-llms-txt`. Every link must resolve (`llms-txt-links-resolve`) and carry a
- short description (`llms-txt-formatting`).
-
- ### 6.2 `/.well-known/ard.json` (Agentic Resource Discovery)
-
- ARD v0.91 canonical path; keep `/.well-known/ai-catalog.json` as the equivalent
- predecessor alias. Each entry names a resource with a `urn:air` identifier, a media
- type, and exactly one of `url` or `data`:
-
- ```json
- {
- "catalog": {
- "id": "urn:air:example.com:catalog",
- "name": "Example Site",
- "entries": [
- {
- "id": "urn:air:example.com:mcp:docs",
- "name": "Docs MCP",
- "mediaType": "application/json",
- "url": "https://example.com/mcp"
- }
- ]
- }
- }
- ```
-
- `ard-trust-manifest` adds the provenance/trust block alongside the entries.
-
- ### 6.3 `/.well-known/agent-skills/index.json` v0.2.0
-
- ```json
- {
- "version": "0.2.0",
- "skills": [
- {
- "name": "example-skill",
- "description": "What the skill does",
- "url": "https://example.com/.well-known/agent-skills/example-skill.md",
- "digest": {
- "algorithm": "sha256",
- "value": "sha256:..."
- }
- }
- ]
- }
- ```
-
- The digest is a real `sha256:` of the referenced document — recompute it whenever the
- document changes, or the index is silently invalid.
-
- ### 6.4 `pricing.md`
-
- For merchant/SaaS sites, publish `/pricing.md` (and keep `/pricing` as the HTML page):
- a plain-markdown table of plans, prices, currency and billing period, plus a one-line
- answer per tier. `pricing-info` also accepts the HTML page; `pricing-md` wants the
- markdown sibling.
-
- ### 6.5 Markdown negotiation
-
- When the request's `Accept` header includes `text/markdown`, serve a markdown rendering
- of the page (or a link to one) and always send:
-
- ```
- Vary: Accept
- Content-Type: text/markdown; charset=UTF-8
- ```
-
- Balanced code fences (`code-fence-validity`) and optional YAML frontmatter
- (`markdown-frontmatter`) are required for a clean markdown response.
-
- ### 6.6 RFC 8288 `Link:` headers
-
- Emit discovery relations on HTML responses, e.g.:
-
- ```
- Link: <https://example.com/llms.txt>; rel="alternate"; type="text/plain",
- <https://example.com/sitemap_index.xml>; rel="sitemap",
- <https://example.com/.well-known/api-catalog>; rel="api-catalog"
- ```
-
- ### 6.7 Agent-friendly 404
-
- Return a real HTTP `404` with a short markdown body that points agents at the sitemap
- and `llms.txt`:
-
- ```
- # 404 — Not found
-
- The page you asked for does not exist.
- - Site map: /sitemap_index.xml
- - Machine summary: /llms.txt
-
- Try one of those, or search the site.
- ```
-
- Never serve a `200` "soft 404"; `agent-friendly-404` checks the status line, not the
- body alone. A soft 404 is not only the missing-page template: probe a made-up top-level slug,
- a made-up nested path, a typo or near-prefix of a real post slug (WordPress's
- `redirect_guess_404_permalink` redirects it to the closest post with `200`) and a made-up
- `.php`/`.html` path, on both the apex and `www` hosts. An apex-to-`www` redirect that sends
- unknown paths to the home page with `200` is a soft 404 too. One passing shape does not pass
- the check.
-
- ### 6.8 JSON-LD identity and breadth
-
- Emit one identity graph (Organization / LocalBusiness) with `contactPoint`, `address`
- and a populated `sameAs` array (entity linking). Add breadth types Rank Math does not
- already emit — `FAQPage`, `Service`, `Product`, `AggregateRating`, `BreadcrumbList` —
- **guarded against duplicate schema sources**: if Rank Math already emits a type, the
- theme must not emit it a second time (§16 of the SEO standards skill).
-
- All of this is for a site with no SEO plugin. When Rank Math, Yoast or SEOPress owns the
- schema, the theme emits no JSON-LD at all — a second identity graph beside the plugin's is
- the duplicate source SEO-039 reports — so GEO-A07 to GEO-A10 cannot be fixed from the
- theme. They are reported as dependent on the SEO plugin's configuration, and
- `wp-audit-rankmath` fills the plugin's Organization / LocalBusiness `contactPoint`,
- `address` and `sameAs` (Rank Math emits neither `contactPoint` nor `address` by default).
-
- ### 6.9 Trust anchors
+ ## 5. Citability
- Ensure `/about`, `/contact`, `/privacy` exist as real published pages with ≥500
- characters each, seeded from the demo header/footer copy. They satisfy both
- `trust-anchors` and give the entity graph something to link to.
+ Citability is a property of the **copy**, not the markup: how likely a generative engine is
+ to lift a passage verbatim. The rubric — five weighted components, an optimal passage of
+ 134-167 words, answer-first openings — and a worked rewrite are in
+ [references/citability.md](references/citability.md).
- ### 6.10 `llms-full.txt` and `auth.md`
+ ## 6. Surfaces
- `/llms-full.txt` is the `/llms.txt` route family carrying the body text of published
- pages and posts (capped at the first 200 — an unbounded dump can exhaust memory on a
- content-heavy site; `/llms.txt` remains the complete index), for agents that ingest the
- whole site. `/auth.md` (SaaS/API only, spec
- §7.3) is the credential walkthrough an agent reads before calling the API — scheme,
- discovery endpoints and a numbered obtain-and-send flow — and satisfies `auth-md-exists`,
- `auth-md-structure` and `auth-md-walkthrough-simulation` (GEO-U08).
+ The fixer writes the theme's `inc/agentic.php`, which owns every surface; all are
+ applicability-gated, so a content site emits no API or payment surface. What each must
+ contain is [references/surface-templates.md](references/surface-templates.md). One rule
+ belongs here because both agents act on it: **when Rank Math, Yoast or SEOPress owns the
+ schema, the theme emits no JSON-LD**, so GEO-A07 to GEO-A10 are fixable only when no SEO
+ plugin owns the graph — otherwise `wp-audit-rankmath` fills it.
---
## 7. Verification loop
The live verifier is `${CLAUDE_PLUGIN_ROOT}/bin/geo-scan.sh <domain|url> [--start]` — run
it, do not read or reimplement it. It needs `curl`; `timeout` or `gtimeout` bound it when
present. It issues a read-only `GET` to the public is-agentic report API
(`https://is-agentic.com/api/v1/report?url=…`) and **only prints the JSON report**. It never
runs npm packages — `/wp-yolo` calls it unattended, so downloading and executing a package
would be a supply-chain risk. When no completed report exists yet, `--start` asks
is-agentic to scan the host through the same HTTP endpoint the npm CLI uses and reads the
report when the scan finishes, all within 110 s. Pass `--start` only for a host the
operator confirmed as public this run: a scan makes is-agentic fetch the site. The script
- does not parse the JSON; the caller — the audit/fix agent — maps the failed ORA check ids
- back to GEO codes using §3, and re-runs the scan after the fixer completes.
+ does not parse the JSON.
| Exit | Meaning | What the caller does |
|---|---|---|
| `0` | a non-empty report came back | map its failed ids to GEO codes |
| `1` | the request failed, or the arguments were wrong | record the error; the GEO codes it would have measured are `UNMEASURED` |
| `2` | skipped cleanly: no `curl`, no network, no completed report, a scan that did not finish, a transient `429`/`503` | record the skip and mark the run incomplete — never a pass |
| `3` | the host is not publicly reachable: `localhost`, `.local`, `.test`, `*.local.com`, a private address, a name with no dot | pass the public URL (`/wp-audit --host`); a dev host is a configuration problem, not a missing report |
- - A fix is reported resolved **only when the ORA check flips**, not when the theme
- file changed.
- - The evaluator reads a point-in-time scan; a green scan is evidence, not a guarantee.
+ The loop:
+ 1. **Scan** the public host and note the report's scan time.
+ 2. **Map** each failed ORA check id to its GEO code with
+ [references/check-catalog.md](references/check-catalog.md).
+ 3. **Fix** what the theme can fix (`wp-agentic-surfaces`); leave advisory codes as
+ recommendations.
+ 4. **Re-scan once**, after the fix is deployed to the host the scan reads.
+ 5. **Compare.** A fix is resolved **only when its ORA check flips** in a report scanned
+ after the fix — never because the theme file changed. A report whose scan time precedes
+ the fix is the old report: `geo-scan.sh` only starts a scan when none exists, so it
+ returns the pre-fix report until is-agentic re-scans the site. Ask the operator to
+ re-scan at https://is-agentic.com; until then the code is `UNMEASURED`, not resolved.
+ Stop after that one re-scan.
+
+ The evaluator reads a point-in-time scan; a green scan is evidence, not a guarantee.
+
---
## 8. Ceilings (documented, not bugs)
- **Off-site checks are advisory.** Wikipedia/Wikidata, registries, ChatGPT app
listings, npm SDK packages and brand share-of-voice are detected and recommended,
never fixed from a WordPress theme.
- - **Payments / AP2 / ACP / UCP / x402 are merchant-only and largely advisory** for
- WooCommerce today.
+ - **Payments / AP2 / ACP / UCP / x402 are merchant-only and advisory** for WooCommerce:
+ no WooCommerce gateway implements an agent payment protocol, so the fixer recommends and
+ never fabricates support.
- **`markdown-negotiation` on edge-cached hosts is CDN-dependent.** The theme route
covers standard PHP hosting; an aggressive CDN cache can serve HTML regardless of the
`Accept` header and must be configured separately.
- **The live scan depends on a publicly reachable URL and the ORA/is-agentic service.**
It skips cleanly when unavailable and the run is marked.
- **The catalog is a moving target.** Counts and weights come from
`GET https://ora.ai/api/checks`; re-fetch it before quoting numbers as current.