---
name: seo-schema-validator
description: |
  Validates an AUTHORED JSON-LD schema dataset (pre-deployment QA) and audits
  live structured data (post-deployment). Runs a 5-layer offline validation
  pipeline (coverage, syntax, vocabulary, Google rich-result requirements,
  business-logic/consistency) and emits a severity-ranked defect log, a gate
  decision, and a Markdown report. Fills the "16-seo-schema-validator" slot
  referenced by seo-comprehensive-audit.
  Triggers: schema validation, JSON-LD QA, structured data check, schema 검수,
  스키마 유효성 검증, 구조화 데이터 검토, rich result eligibility, schema 오류 점검.
version: "1.0"
author: OurDigital / D.intelligence
environment: Code
---

# SEO Schema Validator (16)

Quality-assure structured data at scale. Built for the kind of failure where a
client review of hundreds of authored entries surfaces "too many errors" — by
moving the cheap, machine-checkable errors OUT of the human review and INTO an
automated gate that runs first.

## Two modes

| Mode | When | Input | Adds |
|------|------|-------|------|
| **A — Dataset QA (default)** | Before deployment, while authoring/reviewing | An authored dataset: `.xlsx` / `.csv` (one row per entry, a JSON-LD column), `.jsonl`, `.json`, or a directory of `.json/.jsonld` | Layer 0 coverage vs the canonical URL list |
| **B — Live audit** | After deployment, or feeding `seo-comprehensive-audit` | Live URLs (extract embedded JSON-LD first, then validate) | Layer 5 rendering-reality (schema present in rendered HTML, matches content) |

This skill's primary job is **Mode A**: catch errors before the client sees them.

## The 5 validation layers

| # | Layer | Catches | Default severity |
|---|-------|---------|------------------|
| L0 | Coverage | URLs with no entry; entries whose URL isn't in the inventory | P1 / P2 |
| L1 | Syntax | invalid JSON, missing/wrong `@context`, no `@type`, encoding corruption | P0 / P1 |
| L2 | Vocabulary | unknown type, property not valid for type, bad value formats (URL/date/lang/currency/number) | P1 / P2 |
| L3 | Rich-result | Google **required** missing (blocks rich result); recommended absent | P0 / P2 |
| L4 | Consistency | NAP mismatch across a property, `@id` dupes/dangling refs, swapped geo, placeholder text, duplicate descriptions | P0 / P1 |

Full rationale and the type→requirement matrix: `references/validation-methodology.md`.
Severity + category codes: `references/defect-taxonomy.md`.
Hotel page-type → schema-type map: `references/hotel-type-map.md`.
Client-facing report + P1 decision log: `templates/client-qa-report-template.md`, `templates/decision-log.md`.

## Stage gates (aligned to the project lifecycle 설계→개발→테스트→안정화→런칭 후)

- **G1 설계** — Lock the schema spec and the page-type→type map (`hotel-type-map.md`). Approve the entry template. *DoD:* every page template has an assigned schema type and a required-property list.
- **G2 개발** — Authors produce entries. Run the validator with `--strict`. *DoD (gate):* **zero P0**, JSON parses for 100% of entries. Entries failing this NEVER reach client review.
- **G3 테스트** — Re-run; triage P1 in `defect_log.csv` (assign owner/status). Client reviews ONLY the clean, P0-free entries, against a defect report — not raw JSON. *DoD:* P1 triaged, decisions logged in `templates/decision-log.md`.
- **G4 안정화** — Fix → re-run → confirm no regressions. Spot-check a sample in Google Rich Results Test (online, outside this runtime). *DoD:* P0=0, P1 accepted/closed, online validator green on sample.
- **G5 런칭 후** — Mode B live audit + GSC "Rich results" report monitoring. *DoD:* deployed schema matches authored dataset; no new GSC structured-data errors.

## How to run

```bash
# Mode A — validate an authored dataset (the common case)
python scripts/validate_schema.py path/to/schema_dataset.xlsx \
    --url-list path/to/URLlist.xlsx \
    --out schema_qa_out

# Highest signal for the pre-review gate (unexpected props -> P1, drop optional recommended)
python scripts/validate_schema.py dataset.csv --strict --no-recommended --out qa_strict

# Try it on the bundled flawed fixture first
python scripts/make_sample.py
python scripts/validate_schema.py fixtures/sample_schema.csv --out demo_out
```

**Input expectations (Mode A tabular):** the loader auto-detects a JSON-LD column
(`jsonld`, `schema`, `structured_data`, `스키마`, …) plus optional `url`/`메뉴 URL`,
`lang`/`언어코드`, `device`/`PC/MOBILE`, `page_type` columns. Multi-sheet `.xlsx`
is supported (each sheet with a JSON-LD column is read). No JSON-LD column → clear error.

## Reading the output

- `report.md` — counts, **gate decision (PASS = zero P0)**, defects-by-category, top P0 entries, next step.
- `defect_log.csv` — one row per finding with `status/owner/note` columns ready for triage. This is the client-facing artifact (open issues, not raw schema).
- `results.json` — full machine-readable results for dashboards / CI.

**The rule:** an entry advances to client review only when it has **zero P0**. P1 =
triage backlog (fix before launch). P2 = optimization backlog (recommended props, style).

## Limits & honesty

- Offline by design — the runtime can't reach schema.org or Google. The bundled
  rule set (`scripts/schema_rules.json`) is a curated hotel-focused subset; unknown
  types/properties degrade to warnings (never hard errors) to avoid false positives.
- Authoritative rich-result eligibility still requires Google's online testers on a
  sample at G4. This skill makes that sample small and clean, not redundant.
- Adding a new schema type or tightening a rule = edit `schema_rules.json` only.

## Integration

`seo-comprehensive-audit` calls this skill as pipeline stage 4 ("Schema Validation").
For that orchestrator, run **Mode B** on a sample of live URLs and return the score
(100 − weighted defect penalty) and the issue list. For day-to-day client work, run
**Mode A** on the authored dataset.
