observe/enrich: schema-constrain + drop bare-list fallback
Lock the enrichment output to the documented wrapper shape
{statements, topics, setting, warning} by passing a Draft 2020-12
schema on the generate() call, and drop the bare-list fallback that
was silently wrapping drifted Gemini output with empty metadata.
Four changes:
- observe/enrich.schema.json (new) — wrapper schema, root and item
additionalProperties:false, no minLength (empty strings permitted
on corrected/emotion/topics/setting/warning per prompt contract).
- observe/enrich.py — module-level _SCHEMA load; pass
json_schema=_SCHEMA into generate(); delete the bare-list branch
so non-dict responses fall through the existing isinstance(dict)
guard and return None.
- tests/test_enrich_schema.py (new) — schema validity, accept/reject
matrix, and generate() wiring test, mirroring
tests/test_extract_schema.py.
- tests/test_enrich.py — rewrite test_bare_list_response_wrapped as
test_bare_list_response_returns_none.
Follows the direct-caller schema-constrain pattern established by
observe/extract.py (03bf274d) and think/detect_created.py (b58bd862).
Provider-side json_schema plumbing is already in place; no
think/models.py or provider changes required.