Dataframe escaping, resource error contracts, 422 body parsing
- openaq_dataframe_query escapes backslash/pipe/newlines in rendered Markdown table cells, including header names (#8)
- openaq://location and openaq://parameters declare error contracts (invalid id, not found, upstream 5xx/429/timeout/401) with recovery hints (#20)
- extractValidationMessage reads all four OpenAQ 422 body shapes instead of only the Python-repr array (#21)