# 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 `�` 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 1. Sort `defect_log.csv` by severity (already sorted P0→P1→P2 on write). 2. **P0:** assign an owner, fix, re-run. No P0 may survive into client review. 3. **P1:** set `owner` + `status`, decide fix-now vs accept; log accepted ones in `templates/decision-log.md`. 4. **P2:** schedule into the optimization backlog. 5. Re-run after fixes and confirm no regressions before advancing the stage gate.