{
  "$comment": "Phase 8.1.3 unified error taxonomy. Single source of truth is the ERRORS const in worker.js; this file mirrors it for docs + consumer codegen. Tool-level errors put the CODE in a string `error` field (backward-compatible, machine-readable). HTTP routes return the structured shape { error: { code, message, field? }, code, message, field? } alongside the response envelope (as_of, model_versions, warnings).",
  "version": "p5s12-2026.07",
  "envelope": {
    "success": ["data|<legacy top-level fields>", "as_of", "model_versions{model,underwrite,serving}", "warnings[]"],
    "error": { "error": { "code": "string", "message": "string", "field": "string (optional)" }, "code": "string", "message": "string" }
  },
  "errors": {
    "units_required":               { "http_status": 400, "message": "unit count unknown for this property — pass units", "retryable": false, "where": ["underwrite", "deep_underwrite_asset", "/api/underwrite", "/api/property"] },
    "price_required":               { "http_status": 400, "message": "a positive price is required", "retryable": false, "where": ["underwrite", "deep_underwrite_asset", "/api/underwrite", "/api/property"] },
    "outside_mapped_tracts":        { "http_status": 400, "message": "outside mapped tracts (Cook + Lake County, IL only)", "retryable": false, "where": ["underwrite", "comps", "risk_report", "/api/property"] },
    "tract_not_ingested":           { "http_status": 400, "message": "sales data for this tract is not yet ingested", "retryable": false, "where": ["comps", "get_comps"] },
    "insufficient_renovated_comps": { "http_status": 200, "message": "not enough renovated comps to value confidently — suppressed", "retryable": false, "note": "Tier-3 suppression: no number is emitted (INV-5), reason attached." },
    "dispersion_exceeds_threshold": { "http_status": 200, "message": "comp dispersion exceeds the confidence threshold — suppressed", "retryable": false, "note": "Tier-3 suppression." },
    "luxury_thin_comps":            { "http_status": 200, "message": "luxury stratum has too few comps to value confidently — suppressed", "retryable": false, "note": "Tier-3 suppression." },
    "rate_limited":                 { "http_status": 429, "message": "rate limit exceeded — slow down and retry", "retryable": true, "note": "Anonymous: 30/min/IP. Keyed: per-key rpm_limit token bucket. Retry after ~60s." },
    "invalid_params":               { "http_status": 400, "message": "request failed input validation", "retryable": false, "fields": ["field", "expected"], "note": "Emitted by the JSON-Schema-subset validator before dispatch (type/enum/required/min/max/pattern)." },
    "not_found":                    { "http_status": 404, "message": "resource not found", "retryable": false },
    "unauthorized":                 { "http_status": 401, "message": "authentication required", "retryable": false, "note": "Provide Authorization: Bearer pm_<key> (or WRITE_SECRET for Mo's private rail)." },
    "forbidden_scope":              { "http_status": 403, "message": "your key lacks the required scope", "retryable": false, "note": "Write tools require the write-state scope." },
    "payload_too_large":            { "http_status": 413, "message": "request or response exceeds the size budget", "retryable": false, "note": "Response guards truncate + warn (viewport-context 40KB, search 60KB)." },
    "upstream_unavailable":         { "http_status": 502, "message": "an upstream data source is unavailable", "retryable": true, "note": "A county open-data source (Socrata) or the state store was unreachable." }
  },
  "non_actionable_states": {
    "arv_range_only": { "http_status": 200, "meaning": "An interval is available, but suggested_offer, profit, NOI, DSCR, CoC, strategy_scores, and cashflow are null." },
    "area_estimate_not_property_specific": { "http_status": 200, "meaning": "Area context may be displayed, but it cannot drive property economics." },
    "arv_method_not_actionable": { "http_status": 200, "meaning": "A legacy or unknown value method was rejected as an underwriting basis." }
  }
}
