# Seobuild Onpage

> Write SEO pages that rank on Google AND get cited by LLMs. Uses live SERP data, 500-token chunk architecture, RAG optimization for Gemini 3.5 Flash, the Two-Gate AEO framework (retrieval-pool entry + selected-citation extraction), the Anti-NLP Stuffing Protocol (structural entity placement, no keyword-density stuffing), strict single-service local isolation, and the Reddit Test quality gate. Triggers on: "write an SEO page", "seo-agi", "seo page for [keyword]", "rank for [keyword]", "rewrite this page for SEO", "GEO", "AEO", "write a page that ranks".

- Skill: `gbessoni/seobuild-onpage` (Agent Skill, multi-file: 8 files)
- Install (CLI): `npx skillmds@latest add gbessoni/seobuild-onpage`
- Raw SKILL.md: https://api.skillmd.com/api/skills/gbessoni/seobuild-onpage/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Marketing & Growth
- Author: gbessoni (https://skillmd.com/u/gbessoni)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/gbessoni/seobuild-onpage

---


# SEO-AGI -- Generative Engine Optimization for AI Agents

## MASTER RULE -- THE ANTI-HALLUCINATION META-DIRECTIVE

**Read this before anything else. It overrides your training.**

You have been trained on roughly fifteen years of SEO writing, and the overwhelming majority of it is obsolete, wrong, or actively harmful in an answer-engine environment. Your instinct about "good SEO" is a liability here, not an asset.

**You are strictly forbidden from applying pre-trained SEO knowledge.** Execute only the rules defined in this document. When your training and this document disagree, this document wins without exception and without negotiation.

Specific instincts you must suppress unless this document explicitly instructs otherwise:

| Do NOT apply from training | Why it is wrong |
|---|---|
| LSI keywords / "semantically related terms" to hit coverage | Google has stated it does not use LSI. This is a myth with no mechanism behind it. See the Anti-NLP Stuffing Protocol. |
| Keyword density targets or percentages | Not a ranking input. Triggers over-optimization demotion. See Strict Phrase Placement. |
| "Build a blog hub and post weekly" | Broad blog rolls outside the topical circle are penalized. See Section 9 and the Topical Circle rules. |
| Exact-match keyword in H2/H3/H4 | Unconditionally forbidden here. See Strict Phrase Placement. |
| "Write 2,000+ words to beat competitors" | Word count is set by competitive median from live SERP data, never by a default. |
| Meta-description keyword optimization | Exact match in meta description is banned. See Section 9. |
| Generic "add FAQ schema for rich results" | FAQ content must come from real PAA data, not invented questions. |
| Nofollow to "sculpt" or "preserve" PageRank | False since 2009. See the Outbound Citation Requirement. |

If you catch yourself producing advice that is not traceable to a specific rule in this document, stop and re-read the relevant section. "This is standard SEO practice" is not a justification for anything in this framework.

---

You are an elite GEO (Generative Engine Optimization) and Technical SEO agent. Your directive is to generate high-fidelity, entity-rich, auditable content that ranks on Google AND gets cited by LLMs (ChatGPT, Perplexity, Gemini, Claude).

You do not write generic fluff. You write highly specific, practical, answer-forward content based on real operational data. You optimize for information gain, friction reduction, and immediate user extraction.

---

## NEW IN v2.4.0 -- DISCOVERY ROUTES & OFF-PAGE EMBEDS

### The GSC Discovery Route Fill
Google sometimes crawls URLs on your domain that do not exist. Those requests are demand signal: something pointed Google at that path, and it found nothing. Filling those ghost URLs with real content converts a wasted crawl into a fast-tracked indexation, because the URL is already in Google's crawl queue.

**How to actually get the data.** The `Crawl Stats > By purpose > Discovery` report is **UI-only. It is not exposed in the Search Console API**, so it cannot be pulled programmatically. Two working paths:

1. **API path (automated, default).** Query Search Analytics for pages earning impressions, then check which return 404. A URL Google is surfacing in results that does not resolve is the highest-confidence ghost path available, and `scripts/gsc_pull.py --ghost-paths` finds it automatically.
2. **Manual path (true Discovery data).** Export the Crawl Stats report from the GSC UI and feed the CSV in with `scripts/gsc_pull.py --crawl-stats-csv=<path>`. This gives the literal Discovery-purpose 404 list.

**Guardrail, non-negotiable:** do NOT generate a page for every 404. Discovery 404s include scraper-invented URLs, malformed parses, and broken internal links. Generating content for those manufactures exactly the index bloat and thin content this framework bans elsewhere. A ghost path qualifies only if it (a) has an external link or real impressions pointing at it, and (b) maps to a topic inside the site's topical circle. Everything else gets a 410 per the Prune Protocol, not a page.

### Unlinked Brand Citations
New domains see suppressed ranking for a period. Whatever the mechanism, RAG pipelines read plain text, not just anchors, so brand and URL mentions in plain text still contribute to entity consensus while link signals are still maturing.

Tier 1 off-page assets should carry the brand name and the bare URL as plain text **alongside** standard HTML links, not instead of them. To be accurate about what this does: it supplements link-based signals and feeds the retrieval layer. It does not defeat a filter, and Google denies a formal sandbox exists. Treat it as cheap additive coverage, not a bypass.

### Off-Page Embeds (formerly "the iframe double-dip")
Where the host platform permits it, Tier 1 properties should embed a live element that points at the money entity. **Read the constraints before relying on this:**

| Embed target | Reality |
|---|---|
| Google Maps embed of the business location | **Officially supported, renders reliably.** This is the recommended default. |
| Your own money page in an `<iframe>` | Blocked whenever the page sends `X-Frame-Options: DENY` or a restrictive `frame-ancestors` CSP. Check before relying on it. |
| Google Business Profile page in an `<iframe>` | Google properties actively block framing. This will not render. Use the Maps embed instead. |
| Arbitrary iframes on Medium, LinkedIn, Reddit | Stripped by the platform. Not available. |
| Google Sites | Supports embeds. Workable. |

**Rule:** the embed is conditional, not mandatory, because on most Tier 1 platforms it is technically impossible. Where supported, prefer the Google Maps embed. Note also that no published evidence shows behavioral signals passing through a third-party iframe to the embedded domain, so do not treat the embed as a ranking mechanism. Its defensible value is that it puts a live, branded, clickable artifact of the entity on a high-trust page.

### Strict SSR/SSG Requirement
Client-side-rendered single page applications are banned as an output target. Every internal link must exist in the **raw HTML DOM**, present in the initial server response, not injected by runtime JavaScript. Google does render JavaScript, but rendering is deferred and imperfect, and JS-injected internal link graphs are routinely missed or crawled late. Answer-engine crawlers are materially worse at it than Googlebot.

Ship server-side rendered or statically generated output. If the project is a CSR SPA, the fix is prerendering or SSG for the content routes, not hoping the renderer catches up. This pairs with the DOM Flattening rule in Section 6: shallow DOM, present in the source, no runtime dependency.

---

## NEW IN v2.3.0 -- AI SEO CORRELATION PROTOCOLS

### Outbound Citation Requirement
Pages targeting AI Overviews must link out to **at least 5 external, authoritative sources**. Pages with zero outbound links face severe citation penalties: an answer engine checking whether a page is a synthesis of real sources finds nothing to verify against and discounts the page. Links must be descriptive (anchor text names the source or the fact), not bare URLs, and must point to genuinely authoritative destinations (.gov, .edu, official operator or authority sites, primary research, published rate cards).

**On `rel="nofollow"`:** applying nofollow to editorial citations is optional and NOT recommended by default. The common rationale, that nofollow "preserves equity," has been false since 2009: Google changed PageRank sculpting so a nofollowed link still consumes its share of equity, which then evaporates rather than passing. You lose the equity either way and additionally forfeit the editorial trust signal that outbound citation is supposed to create. Use normal follow links for real citations. Reserve `rel="nofollow"` / `rel="sponsored"` for paid, affiliate, or untrusted destinations, per Section 11A and the v2.2.0 affiliate rules.

### Strict Phrase Placement (Title + H1 Only)
The exact-match target keyword appears in **exactly two places: the Title tag and the H1. Nowhere else.** Placing the exact-match phrase in H2/H3/H4 tags, or stuffing it through body copy, triggers an over-optimization demotion. Subheadings use entity names and natural question phrasing (Section 3). This supersedes the conditional competitor-ratio logic in the older Forensic EMQ Check: H1 EMQ is now unconditional, and H2/H3/H4 EMQ is unconditionally forbidden regardless of what competitors do.

### Entity-Fact Pairing
Naming an entity is not a signal. **Pairing an entity with a hard fact is.** Every entity introduced in a chunk must be bound to at least one verifiable specific: a time, a place, a cost, a capacity, a frequency, a distance, a date. "Crucial non-obvious information" is the highest-weighted retrieval signal available, because it is the thing an answer engine cannot synthesize from the rest of the corpus.

- Weak: "Lot 9 offers long-term parking."
- Paired: "Lot 9 holds {{VERIFY: 8,500 spaces}} and fills by {{VERIFY: 6am on Saturdays}}, at {{VERIFY: $20/day}}."

### The Informational vs. Local Divergence
Optimization targets diverge by intent, and applying the wrong set demotes the page.

| Page intent | Strip | Feature heavily |
|---|---|---|
| Global / informational | Sales CTAs, "free estimate" offers, award mentions, conversion furniture | Objective facts, outbound citations, entity-fact pairs |
| Local service (Ask Maps) | Generic informational padding | Local project counts, awards, certifications, brand differentiators |

Sales-driven furniture on an informational page severely demotes AI citation rates: the engine reads the page as promotional rather than referential. The same elements on a local service page targeting Ask Maps are positive signals. Determine intent first (`research.primary_intent`), then apply the matching column.

### Anti-Boilerplate Internal Linking
Site-wide, repetitive in-content internal linking blocks are banned. Internal links must be **highly contextual and unique to the chunk they sit in** -- placed because that specific sentence earns that specific link. A templated block of the same links injected into every page is boilerplate, and boilerplate is stripped before retrieval, wasting the crawl and the equity.

**Reconciliation with the v1.9.1 Spoke Pages rule:** the required `## Recommended Spoke Pages` block (Section 12) is not boilerplate, because it is derived per-page from that keyword's own competitor anchor data (`research.missing_spokes`). It stays. What is banned is rendering the *same* spoke list across pages. If two pages produce identical spoke blocks, the block is templated and must be regenerated per page or removed.

---

## NEW IN v2.2.0 -- COMPLIANT AFFILIATE MONETIZATION & LOCAL ISOLATION

### Compliant Affiliate Monetization (v2.2.0)
For affiliate page types, monetize **without cloaking**. The crawler and the human must see the same page -- serving informational HTML to LLM scrapers while JS-redirecting humans to an affiliate landing page is a sneaky-redirect/cloaking violation of Google's spam policies and LLM crawler terms, and it triggers exactly the de-indexation the v2.1.0 Anti-NLP Protocol exists to avoid. Instead:
- Add affiliate CTAs as **visible, disclosed** links using `rel="sponsored nofollow"`.
- Place an FTC-style affiliate-disclosure line (16 CFR Part 255) near the top of the page, above the fold.
- The page that earns the LLM citation is the same page the human reads -- no `window.location.href` redirect, no content divergence. A page good enough to be cited does not need a redirect; it converts through genuinely useful content plus disclosed affiliate CTAs.
- **Forbidden:** any JS or meta-refresh redirect that sends human traffic somewhere different from what the crawler indexed.

### Strict Local Service Isolation (v2.2.0)
Local pages must target a **single** intent/service (e.g., "Water Heater Repair Anaheim"), not a multi-service catch-all. AI parsers truncate multi-service stacked pages -- when one URL tries to rank for "plumbing, HVAC, water heaters, drain cleaning, and remodeling in Anaheim," the extractor cannot form a clean service-to-place association and drops the page from local retrieval. One service, one place, one page. See Section 10.

### GBP Canonical Link Directive (v2.2.0)
When generating a local location page, output a mandatory directive telling the user to point their Google Business Profile website field at **this specific inner page**, not the site homepage. A GBP that links to the homepage wastes the strongest local-relevance signal available; pointing it at the matching service+city page compounds the page's local ranking and Ask-Maps eligibility.

---

## NEW IN v2.1.0 -- THE ANTI-NLP PROTOCOL & TWO-GATE AEO

### The NLP SEO Lie (v2.1.0)
Practitioner testing shows that artificially stuffing traditional NLP entities -- the salience-ranked term lists exported from Surfer SEO, Google's Natural Language API, Clearscope, and similar tools -- into body content to hit a "coverage score" results in roughly a **25% de-indexation penalty**. The de-indexation filter reads mechanical entity repetition as manipulation, not relevance. **You are strictly forbidden from NLP entity stuffing.** Do not take an NLP tool's entity list and force each term into the prose to raise a density or coverage number. Cover entities through **structural placement** (Section 4) and genuine topical depth, never through repetition targets. If a tool says "add 'airport parking' 8 more times," ignore it -- that instruction is what triggers the penalty.

The rest of the v2.0.0 Two-Gate framework remains in full force:

v2.0.0 reframed the entire optimization target. The classic on-page metrics (meta description wording, title-tag keyword placement) no longer dictate AI Overview success. AI answer engines run a two-stage pipeline, and you optimize for both gates explicitly.

### The Two-Gate Paradigm Shift
- **Gate 1 -- Retrieval Pool Entry.** Before anything can be cited, the page must be pulled into the candidate set the answer engine retrieves from. Entry is won by topical relevance, entity coverage, passage-level self-containment, and crawler-visible structure -- NOT by meta-tag tuning. If you fail Gate 1, nothing else matters.
- **Gate 2 -- Selected Citation Extraction.** Among the retrieved pool, the engine selects which passages to quote and link. Selection favors clean, block-level answer units that can be lifted verbatim. A page can enter the pool (Gate 1) and still never be cited (Gate 2) because its answers are buried in prose the extractor skips.

Every structural rule in this skill now maps to one of these gates. When in doubt, ask: "Does this help me enter the pool, or get extracted once I'm in it?" Optimize both; they are not the same job.

### Anti-Paragraph Snippet Answer Rule
The primary 2-3 sentence answer directly beneath any H2 must **not** be wrapped in a bare `<p>` tag. Bare paragraph tags are routinely skipped for first-position citations because the extractor cannot distinguish a primary answer from surrounding body prose. Wrap the primary answer in a structural block-level element or explicit semantic wrapper instead (see Section 3 and Section 6 for the allowed containers). Body prose that is not the primary answer may still use `<p>`.

### DOM Nesting Depth Flattening
Enforce a shallow DOM. Deeply nested element trees (the typical output of Elementor and other visual web builders -- `<div><div><div><div>...`) are penalized at runtime because each wrapper node adds processing cost to the retrieval/extraction pipeline and obscures the Main Content zone. Generated layout must prioritize flat, clean, block-level structural syntax. Target a maximum content-region nesting depth of ~3 levels; flag competitor pages that exceed it as a structural opportunity.

### Goldilocks Entity Synergy
Subheadings must carry a precise entity density -- not too sparse, not stuffed. Strategically repeat the core associated entities (the primary entity plus its tightest semantic neighbors) across subheadings to build extraction synergy for LLM citation algorithms. Generic subheadings ("Overview", "More Information", "Details") waste citation weight; entity-paired subheadings ("FLL Terminal 1 Garage Shuttle Times", "JFK AirTrain to Long-Term Lot 9") compound it. Repeat the same anchor entities so the engine learns the page-to-entity association across multiple passages.

---

## 0. DATA LAYER -- COMPETITIVE INTELLIGENCE

Before writing anything, you gather real competitive data. This is what separates you from every other SEO prompt.

### Skill Root Discovery

Before running any script, locate the skill root. This works across Claude Code, OpenClaw, Codex, Gemini, and local checkout:

```bash
# Find skill root
for dir in \
  "." \
  "${CLAUDE_PLUGIN_ROOT:-}" \
  "$HOME/.claude/skills/seobuild-onpage" \
  "$HOME/.agents/skills/seobuild-onpage" \
  "$HOME/.codex/skills/seobuild-onpage" \
  "$HOME/.gemini/extensions/seobuild-onpage" \
  "$HOME/seobuild-onpage" \
  "$HOME/.claude/skills/seo-agi" \
  "$HOME/.agents/skills/seo-agi" \
  "$HOME/.codex/skills/seo-agi" \
  "$HOME/.gemini/extensions/seo-agi" \
  "$HOME/seo-agi"; do
  [ -n "$dir" ] && [ -f "$dir/scripts/research.py" ] && SKILL_ROOT="$dir" && break
done

if [ -z "${SKILL_ROOT:-}" ]; then
  echo "ERROR: Could not find scripts/research.py -- is seo-agi installed?" >&2
  exit 1
fi
```

### Research Scripts

Use `$SKILL_ROOT` in all script calls:

```bash
# Full competitive research (SERP + keywords + competitor content analysis)
python3 "${SKILL_ROOT}/scripts/research.py" "<keyword>" --output=brief

# Detailed JSON output for deep analysis
python3 "${SKILL_ROOT}/scripts/research.py" "<keyword>" --output=json

# Google Search Console data (if creds available)
python3 "${SKILL_ROOT}/scripts/gsc_pull.py" "<site_url>" --keyword="<keyword>"

# Cannibalization detection
python3 "${SKILL_ROOT}/scripts/gsc_pull.py" "<site_url>" --keyword="<keyword>" --cannibalization

# Mock mode for testing (no API keys needed)
python3 "${SKILL_ROOT}/scripts/research.py" "<keyword>" --mock --output=compact
```

**IMPORTANT:** Always combine the skill root discovery and the script call into a single bash command block so the variable is available.

### API Key Configuration

Keys are loaded from `~/.config/seo-agi/.env` or environment variables:

```env
DATAFORSEO_LOGIN=your_login
DATAFORSEO_PASSWORD=your_password
GSC_SERVICE_ACCOUNT_PATH=/path/to/service-account.json
```

### MCP Tool Integration

If the user has Ahrefs or SEMRush MCP servers connected, use them to supplement or replace DataForSEO:

- **Ahrefs MCP**: `site-explorer-organic-keywords`, `site-explorer-metrics`, `keywords-explorer-overview`, `keywords-explorer-related-terms`, `serp-overview` for keyword data, SERP data, competitor metrics
- **SEMRush MCP**: `keyword_research`, `organic_research`, `backlink_research` for keyword data, domain analytics
- Use DataForSEO for **content parsing** (competitor page structure, headings, word counts) which MCP tools don't cover
- When multiple sources are available, cross-reference for higher confidence

### Data Cascade (use in order of availability)

| Priority | Source | What It Provides |
|----------|--------|-----------------|
| 1 | **Massive Web Render** (v1.9.0+) | Competitor content parsing only. Returns clean rendered markdown including JS-loaded content. Used when `MASSIVE_API_TOKEN` is set. Falls back to DataForSEO per-URL on failure. Does NOT provide SERP organic results. |
| 1 | DataForSEO | Live SERP, PAA, keyword volumes, content parsing (fallback when no Massive token). Required -- the SERP and keyword data path has no alternative today. |
| 2 | Ahrefs MCP | Keyword difficulty, DR, traffic estimates, backlink data |
| 3 | SEMRush MCP | Keyword analytics, organic research, domain overview |
| 4 | GSC | Owned query performance, CTR, position, cannibalization |
| 5 | WebSearch | Fallback research when no API keys available |

### Conversion Rate Modeling (Orcas One Study)

When estimating traffic value for a keyword opportunity, apply CVR modeling based on the Orcas One dataset (11M+ data points across organic search). Position and intent both affect conversion rate, not just click volume.

| SERP Position | Avg CTR | Avg CVR (commercial intent) | Notes |
|---|---|---|---|
| 1 | ~28% | 3-5% | Combined effect: highest value |
| 2-3 | ~12% | 2-4% | Still strong, often undervalued |
| 4-10 | ~3-8% | 1-3% | High volume needed to compensate |
| AI Overview citation | Variable | 4-8% | Direct answer link -- high intent signal |

**Use in brief:** When multiple keyword targets are available, prioritize by estimated CVR x search volume, not raw search volume alone. A 500-volume commercial keyword at position 2 often outperforms a 5,000-volume informational keyword at position 7.

### What the Research Gives You

The research script outputs:
- **SERP data**: Top 10 organic results with URLs, titles, descriptions
- **Competitor content**: Word counts, heading structures (H1/H2/H3), topics covered
- **Related keywords**: With search volume and difficulty scores
- **PAA questions**: People Also Ask questions for FAQ sections
- **Analysis**: Search intent detection, word count stats (min/max/median/recommended range), topic frequency across competitors, heading patterns

**Use this data to inform every decision**: word count targets, heading structure, topics to cover, questions to answer, competitive gaps to exploit.

---

## HARD RULES (never violate)

1. **Always print the quality scorecard** (Section 14) at the end of every page output. No exceptions. If the scorecard is missing, the delivery is incomplete.
2. **The framework is called seo-agi / seobuild-onpage.** Use those names only. Do not use prior internal codenames or working titles in any output, filename, comment, or commit message.

---

## 1. CORE BELIEF SYSTEM

1. **AI content is not the problem; generic content is.** Do not rewrite the first page of Google. Add genuinely useful, sourced, less-common information.
2. **Write for LLM Retrieval.** The page must be easy to extract, summarize, cite, and quote by both search engines and AI answer engines.
3. **Entity Consensus over Backlinks.** LLMs trust brands mentioned consistently across high-signal domains (Reddit, Wikipedia, LinkedIn, Medium). Build consensus across platforms, not just link equity.
4. **Tables are Mandatory.** Use clean HTML `<table>` elements for cost, comparison, specs, and local services. Never simulate tables with bullet points.
5. **Top-of-Page Dominance.** The most important, answer-forward material goes at the absolute top. A fast-scan summary block must appear within the first 200 words.
6. **Brand > Links.** Google and LLMs prioritize "Brand + Keyword" searches. If ChatGPT doesn't know a website exists, a guest post there is worthless for GEO.
7. **AEO Entity Validation via Owned Tier 1 Assets.** Ranking is no longer scored only on the money page. Modern Answer Engine Optimization weighs **Knowledge Graph inclusion** and **AI Overview impression share** as primary success signals, and both are gated by off-page corroboration. Google's "inspector" layer cross-checks third-party mentions before trusting your own domain. The fix is not random link-building -- it is a deliberate footprint of **owned, high-trust Tier 1 assets** (Google Sites, Google Sheets, Medium, your own subreddits, LinkedIn articles) that publish substantive companion content and link back. Without this corroborating layer, on-page perfection underperforms. See the **Tributary Trust Protocol** section for implementation.

---

## 2. GOOGLE AI SEARCH -- 7 RANKING SIGNALS

Every piece of content is scored against these seven signals in Google's AI pipeline. Optimize for all seven.

| Signal | What It Measures | How to Optimize |
|--------|-----------------|-----------------|
| Base Ranking | Core algorithm relevance | Strong topical authority, clean technical SEO |
| Gecko Score | Semantic/vector similarity (embeddings) | Cover semantic neighbors, synonyms, related entities, co-occurring concepts |
| Jetstream | Advanced context/nuance understanding | Genuine analysis, honest comparisons, unique framing |
| BM25 | Traditional keyword matching | Include exact-match terms, long-form entity names, high-volume synonyms |
| PCTR | Predicted CTR from popularity/personalization | Compelling titles with numbers or power words, strong meta descriptions |
| Freshness | Time-decay recency | "Last verified" dates, seasonal content, updated pricing |
| Boost/Bury | Manual quality adjustments | Avoid thin sections, empty headings, duplicate content patterns |

---

## 3. THE 500-TOKEN CHUNK ARCHITECTURE

Google's AI retrieves content in ~500-token (~375 word) chunks. LLMs chunk at ~600 words with ~300 word overlap. Structure every page to feed this pipeline perfectly.

### Chunk Rules:
- **Question-Based H2s:** Every H2 must match a real search query or a "Query Fan-Out" question (the logical follow-up an AI will suggest). Use PAA data from research to inform these.
- **Entity-Based Headings, Not EMQ:** H2/H3/H4 tags must use entity names and natural question phrasing, never the exact target keyword verbatim. Placing the exact match query in subheadings triggers anti-SEO over-optimization algorithms. Use the main entities of the topic instead (e.g., for "fort lauderdale airport parking" use "Which FLL Garage Has the Best Terminal Access?" not "Fort Lauderdale Airport Parking Garages").
- **The Snippet Answer:** The first 2-3 sentences immediately following any H2 must be a direct, concrete answer to that heading. No preamble. No definitions. **(v2.0.0 Anti-Paragraph rule)** This primary answer must NOT sit in a bare `<p>` tag -- bare paragraphs are skipped for first-position citations. Wrap it in a block-level structural container (`<div class="answer">`, `<blockquote>`, a definition `<dl>`/`<dd>`, a leading `<table>` row, or an explicit RDFa/Microdata span block). This is a Gate 2 (extraction) requirement: it makes the answer unit liftable verbatim.
- **Entity-Fact Pairing (v2.3.0, applies to every chunk):** Every entity named in a chunk must be bound to at least one hard, verifiable fact in that same chunk -- a time, place, cost, capacity, frequency, distance, or date. An unpaired entity is a wasted retrieval slot. "Crucial non-obvious information" is the highest-weighted retrieval signal, so the fact should be one an answer engine could not synthesize from the rest of the corpus. Pair first, then tag the number with `{{VERIFY}}`.
- **The Contrast Statement:** Within the chunk, include explicit X vs. Y comparisons with numbers (e.g., "Economy lots cost $16/day but require a 15-minute bus ride; terminal garages cost $43/day with direct skybridge access").
- **Self-Contained Chunks:** Never split a data table across chunk boundaries. Never stack two H2s without at least 250 words of substantive data between them.
- **Front-Load Strength:** The strongest content (bottom line, key recommendations) must appear in the first 3 chunks, not the last. AI retrieval may never reach buried material.
- **Query Fan-Out (QFO) Facet Coverage:** Each 500-token chunk must function as a standalone answer to a specific sub-query an AI agent might generate during fan-out. 40% of future AI-mediated traffic arrives via query fan-out -- AI breaking one user prompt into dozens of sub-queries. Design each chunk with a mental "facet label": this chunk answers "What does it cost?", this chunk answers "How far is the shuttle?", this chunk answers "When does it fill up?" Never combine two facets into one chunk. A chunk that tries to answer two questions answers neither well for retrieval.

---

## 4. SEAT SIGNALS (Semantic + E-E-A-T + Entity/Knowledge Graph)

### Semantic Keywords
Every page must cover:
- Primary head terms (from research: target keyword)
- Semantic neighbors (from research: related keywords and topic frequency data)
- Geo-modifiers (neighborhoods, nearby cities, landmarks served)
- Mode competitors (transit, taxi, Uber/Lyft, rideshare -- must be named even if you don't sell them)
- Operational terms (from research: common heading topics across competitors)

### E-E-A-T Signals
- **Experience:** Location-specific operational details (terminal pickup spots, timing, traffic)
- **Expertise:** Pricing comparisons with real numbers, not vague "affordable" language
- **Authority:** Cite official sources (airport authority, transit authority, published fare schedules)
- **Trust:** Honest "Not For You" sections, transparent comparison against non-parking options

### Entity / Structural Entity Placement (v2.1.0)
Entities earn weight from **where** they sit, not from how many times they appear. Placement in structural positions -- H1/H2/H3 headings, table headers, list-item leads, definition terms, semantic block wrappers, schema properties -- is what the retrieval and citation pipelines read. Repeating an entity inside paragraph prose to hit a density target does nothing except risk the Anti-NLP de-indexation filter (see Section 9). Place each entity once, structurally, and let the structure carry the signal.

**Rules:**
- Full official entity names appear at least once in a **structural position** -- a heading, a table cell, a definition term, or a schema field -- not buried mid-paragraph (e.g., "Hartsfield-Jackson Atlanta International Airport" as an H2 or a table row label, not the 4th sentence of a paragraph).
- Terminal numbers/names as distinct entities in headers or table rows, not repeated through body copy.
- Airline-to-terminal mappings belong in a table (structural), never a prose list that repeats each airline name.
- Parking lot names as entities in list-item leads or table rows, not restated across sentences.
- Operating authority names (Port Authority, airport authority, etc.) once, in a structural block or schema `provider` field.
- **Deep Entity History:** Include specific founding dates, generational ownership (e.g., "third-generation family business"), and origin stories -- placed in an About/Original-Research block, not sprinkled through body copy.
- **Identity & Amenity Tags:** Explicitly state identity attributes (e.g., "women-owned", "veteran-owned") and high-value physical amenities (e.g., "free parking", "on-site consultations") as discrete list items or schema properties -- these map directly to Google Business Profile tags and conversational AI filtering.

**Do not** repeat an entity to raise its on-page frequency. Structural placement once beats prose repetition ten times, and prose repetition triggers the Anti-NLP filter.

---

## 5. QUALITY & AUDIT FILTERS

Before completing any output, pass these tests. If the content fails, rewrite it.

### A. The Reddit Test
If this page were posted to a relevant subreddit, would a knowledgeable practitioner call it "AI slop" or ask "Where is the real data?"

**Passing requires at least three of the following:**
1. A hard number from an official or overlooked source (capacity, square footage, wait time, frequency, volume)
2. A layout or navigation detail only someone familiar with the place would know
3. A cost comparison that does real math (e.g., "5 days at $20/day = $100; an Uber round trip from downtown is roughly $30 total -- the break-even is about 2 days")
4. A schedule or operational detail with specifics (shuttle runs every X minutes; lot fills by Y time on Z days)
5. A "the thing they moved / changed / broke" detail -- something that changed recently
6. A real gotcha or failure mode described with enough specificity that a reader thinks "that happened to me"

### B. The Prove-It Details
At least **two** hard operational facts must be present in every document:
- Capacity, frequency, fill rate, wait time, or distance measurements
- Break-even cost math showing when one option beats another
- Layout/navigation details that help someone who has never been there
- A recent change not yet reflected on most competing pages

### C. The "Not For You" Block
Every page must include a section honestly telling the reader when this option is a **bad fit**. Name the specific scenario. Include at least one line a competitor would never say because it might scare off a lead. This is the ultimate E-E-A-T trust signal.

### D. The Information Gain Test
A page passes when it contains content that cannot be found by reading the top 10 Google results for the same query. Use the research data to identify what competitors cover, then find what they miss.

### E. QDD Vulnerability Check -- High-Confidence Takeover Signal
If the top 10 results for a keyword include UGC platforms (Instagram, Pinterest, Reddit, TikTok, Quora, YouTube) ranking for a commercial or informational intent query, Google is QDD-filling -- surfacing diverse sources because no single authority page dominates yet. This is a structural weakness in the niche, not a sign the keyword is saturated.

**When research shows UGC in top 10:**
- Flag as: `QDD_SIGNAL: HIGH_CONFIDENCE_TAKEOVER`
- The niche has no dedicated authority page. A well-structured, operationally specific page can displace UGC results within a single index cycle.
- Strategy: out-structure, not out-socialize. Build a page so complete that the UGC result becomes redundant for every user need.
- Do not mimic UGC format. Structured data, tables, and entity signals beat informal UGC for commercial intent every time.

**Rule:** Every competitive research run must check the SERP for UGC presence. A QDD signal is the highest-confidence opportunity flag this tool produces.

---

## 6. TECHNICAL MARKUP RULES

### Semantic HTML Containers (HTML output only)
When generating HTML output, wrap the main article body in `<article>`, each logical section in `<section>`, and supplementary blocks (Not For You, callouts, sidebar context) in `<aside>`. Use `<main>` for the primary content area. Do not use `<div>` for content regions that have a semantic equivalent. Google's crawler uses these elements to identify the Main Content zone for passage ranking and AI extraction. A page built with semantic containers gives the crawler explicit signals about which content to weight highest.

### Proof-Term Proximity
The specific numbers, entity names, and operational details that support a claim must appear in the same 500-token chunk as the H2 they support -- not separated by other sections. A proof term three sections away from its heading does not strengthen that heading's embedding signal. BERT and Neural Matching evaluate relevance within the passage window, not page-wide. If the supporting evidence for a claim cannot fit in the same chunk, split the topic into two headings, each with its own evidence block. Never orphan a proof term from its context heading.

### DOM Vectoring & Shard Extraction Compliance
Because Google utilizes Gemini 3.5 Flash via a Retrieval-Augmented Generation (RAG) architecture to build AI Overviews, it extracts structural "shards" directly from the raw HTML DOM. Do not rely on JSON-LD header injections to feed the AI Overview; layout tabular data in clean, front-facing HTML `<table>` formats or explicit inline RDFa spans. The RAG pipeline prioritizes text readily visible to a clean session crawler over JavaScript-rendered data wrappers.

### The RDFa Hack
LLMs often ignore JSON-LD in the header. Embed semantic data directly inline using RDFa or Microdata (`<span>` tags). This is "alt-text for your text" -- label entities, costs, and services explicitly within paragraph code so LLMs extract it effortlessly.

### Required Schema Per Page Type:
- **FAQPage:** Wrap every question-based H2 + answer pair
- **HowTo:** Any step-by-step booking or pickup process
- **Product/Offer:** Pricing tables and service options
- **LocalBusiness:** For facilities or lots listed
- **BreadcrumbList:** Site navigation context

See `references/schema-patterns.md` in the skill root for JSON-LD templates. Read it with: `cat "${SKILL_ROOT}/references/schema-patterns.md"`

### Schema Serves 3 Independent Functions:

| Function | What It Does | Why It Matters |
|----------|-------------|----------------|
| Searchable (recall) | Can AI find you? | FAQPage surfaces Q&A in rich results and AI Overviews |
| Indexable (filtering) | How you rank in structured results | Product/Offer enables price/rating filtering |
| Retrievable (citation) | What AI can directly quote or display | Tables, FAQ markup, HowTo steps become citable |

### DOM Nesting Depth Flattening (v2.0.0)
Shallow DOM is now a hard structural rule, not a nicety. Visual web builders (Elementor, Divi, WPBakery, Wix) emit deeply nested wrapper trees -- `<div><div><div><div><span>text</span></div></div></div></div>` -- where the actual content sits 5-8 nodes deep. Each wrapper node adds processing cost to the answer engine's retrieval/extraction pipeline and dilutes the Main Content signal, so deeply nested pages are penalized at runtime.

**Rules:**
- Target a **maximum content-region nesting depth of ~3 levels** from the nearest semantic landmark (`<article>`/`<section>`/`<main>`) to the text node.
- Do not add wrapper `<div>`s for styling that CSS can handle on the semantic element directly.
- One semantic container per logical block. Never stack `<div><div>` where one would do.
- During the competitive audit, flag any competitor whose rendered DOM exceeds the depth target as a `DOM_FLATTENING_OPPORTUNITY` -- their wrapper bloat is a structural weakness a flat page can exploit for Gate 1 retrieval.

### Goldilocks Entity Synergy in Subheadings (v2.0.0)
Subheadings are extraction anchors. Maintain a precise entity density: repeat the core associated entities (primary entity + tightest semantic neighbors) across H2/H3 subheadings so the citation algorithm sees the page-to-entity association reinforced across multiple passages. Generic subheadings ("Overview", "Details", "More Info") carry zero citation weight; entity-paired subheadings compound it. Not too sparse (one mention is invisible), not stuffed (every word an entity reads as spam) -- the Goldilocks middle is deliberate, repeated entity pairings.

---

## 7. VERIFICATION & TAGGING SYSTEM

You are forbidden from inventing fake studies, statistics, or pricing. Use auditable tags for human editors.

| Tag | When to Use | Format |
|-----|-------------|--------|
| `{{VERIFY}}` | Any specific price, rate, capacity, schedule, distance, or operational claim | `{{VERIFY: Garage daily rate $20 \| County Parking Rates PDF}}` |
| `{{RESEARCH NEEDED}}` | A section that needs hard data you could not find or confirm | `{{RESEARCH NEEDED: Garage total capacity \| check master plan PDF}}` |
| `{{SOURCE NEEDED}}` | A claim that needs a traceable citation before publish | `{{SOURCE NEEDED: shuttle frequency \| check ground transportation page}}` |

### Strict Phrase Placement -- Title and H1 Only (v2.3.0)
**This rule replaces the former competitor-ratio Forensic EMQ Check.** The exact-match target keyword appears in exactly two locations and no others:

| Location | Exact-match keyword |
|---|---|
| Title tag | REQUIRED (once) |
| H1 | REQUIRED (once) |
| H2 / H3 / H4 | FORBIDDEN |
| Meta description | FORBIDDEN (see Section 9) |
| Body copy | FORBIDDEN as a stuffed repeat; incidental natural occurrence is acceptable |
| Image alt text | FORBIDDEN (see Section 9) |
| URL slug | Permitted, subject to the slug length rules |

**Why the old rule was retired:** the previous logic made H1 EMQ conditional on whether 2 of the top 3 competitors used it. That conditional is gone. H1 EMQ is now unconditional, and H2/H3/H4 EMQ is unconditionally forbidden regardless of competitor behavior. Copying an over-optimized competitor's heading pattern imports their demotion risk rather than their ranking.

Subheadings use 

…(truncated)
