Defect Taxonomy
Every code validate_schema.py can emit, its default severity, and what to do.
The validator writes these to defect_log.csv (columns: entry_id, url, node_type, layer, code, severity, message, status, owner, note) and results.json.
Severity model
| Severity |
Definition |
Owner action |
| P0 |
Blocker — breaks parsing, blocks the rich result, or ships wrong/placeholder data. Fails the gate. |
Must fix before the entry reaches client review. |
| P1 |
Real defect, doesn't block the rich result. |
Fix before launch; track in the triage log. |
| P2 |
Optimization — recommended properties, formatting, orphan URLs. |
Backlog; fix opportunistically. |
--strict promotes vocabulary/format warnings (and unknown types) from P2 to P1 and
turns on UNEXPECTED_PROPERTY. --no-recommended drops MISSING_RECOMMENDED entirely.
Neither changes the gate — the gate is always "zero P0."
Code reference
Layer 0 — Coverage
| Code |
Sev |
Trigger |
Fix |
COVERAGE_MISSING |
P1 |
Inventory URL has no authored entry. |
Author the entry, or remove the URL from the inventory. |
COVERAGE_ORPHAN |
P2 |
Entry URL isn't in the inventory. |
Fix the URL typo, or update the canonical list. |
Layer 1 — Syntax
| Code |
Sev |
Trigger |
Fix |
INVALID_JSON |
P0 |
JSON does not parse. |
Fix the JSON (trailing comma, unquoted key, smart quotes). |
NO_SCHEMA_IN_HTML |
P0 |
Live page has no ld+json block (Mode B). |
Confirm the tag deployed and renders. |
MISSING_CONTEXT |
P1 |
No top-level @context. |
Add "@context": "https://schema.org". |
WRONG_CONTEXT |
P1 |
@context isn't schema.org. |
Correct the context URL. |
NO_TYPE |
P1 |
No @type anywhere in the entry. |
Add the intended @type. |
ENCODING_CORRUPTION |
P1 |
Replacement char <EFBFBD> present. |
Re-export as UTF-8; check the source pipeline. |
FETCH_ERROR |
P1 |
Live URL could not be fetched (Mode B). |
Check the URL/network; retry. |
Layer 2 — Vocabulary & value formats
| Code |
Sev (strict) |
Trigger |
Fix |
UNKNOWN_TYPE |
P2 (P1) |
@type not in the curated rule set. |
If intended, add it to schema_rules.json; else correct the type. |
UNEXPECTED_PROPERTY |
— (P1) |
Property unknown for a known type (strict only). |
Remove the typo'd property, or add it to the type's allowed. |
BAD_URL |
P2 (P1) |
A URL property isn't an http(s) URL. |
Use an absolute URL. |
BAD_DATE |
P2 (P1) |
A date property isn't ISO-8601. |
Use YYYY-MM-DD (or full datetime). |
BAD_LANG |
P2 (P1) |
inLanguage/availableLanguage isn't a BCP-47 code. |
Use ko, en, ja, zh, … |
BAD_CURRENCY |
P2 (P1) |
priceCurrency isn't a 3-letter ISO-4217 code. |
Use KRW/USD, not ₩/$. |
BAD_NUMBER |
P2 (P1) |
A numeric property isn't numeric. |
Remove units/commas; keep digits. |
Layer 3 — Rich-result requirements
| Code |
Sev |
Trigger |
Fix |
MISSING_REQUIRED |
P0 |
A Google-required property is absent. |
Add the property — the rich result is blocked without it. |
MISSING_RECOMMENDED |
P2 |
Recommended properties absent (one line per node, lists all). |
Add what applies to improve eligibility/appearance. |
Layer 4 — Consistency
| Code |
Sev |
Trigger |
Fix |
PLACEHOLDER_TEXT |
P0 |
Boilerplate token in a string (예시, 수정필요, lorem, {{, …). |
Replace with real content. |
NAP_PHONE_MISMATCH |
P0 |
Same business, different telephone across entries. |
Reconcile to the canonical phone. |
NAP_ADDRESS_MISMATCH |
P0 |
Same business, different streetAddress. |
Reconcile to the canonical address. |
DUPLICATE_ID |
P1 |
One @id defined ≥2× with differing content. |
Make definitions identical, or split the @id. |
DANGLING_ID |
P1 |
{"@id": …} reference to a node never defined. |
Define the node, or fix the reference. |
GEO_SWAPPED |
P1 |
latitude/longitude transposed (swapping fixes it). |
Swap the values. |
GEO_OUT_OF_RANGE |
P1 |
Coordinates impossible (lat∉[-90,90] or lon∉[-180,180]). |
Correct the coordinates. |
DUPLICATE_DESCRIPTION |
P1 |
Same description reused across ≥3 entries. |
Write distinct descriptions per page. |
Triage workflow
- Sort
defect_log.csv by severity (already sorted P0→P1→P2 on write).
- P0: assign an owner, fix, re-run. No P0 may survive into client review.
- P1: set
owner + status, decide fix-now vs accept; log accepted ones in
templates/decision-log.md.
- P2: schedule into the optimization backlog.
- Re-run after fixes and confirm no regressions before advancing the stage gate.