think/detect_created: constrain generation with detect_created.schema.json
Add think/detect_created.schema.json (Draft 2020-12) and pass it as
json_schema= to the existing generate(...) call in detect_created().
This is the first non-talent-dispatcher consumer of the L1 json_schema
kwarg threaded through in c030248d.
Approach mirrors the L3 talent migrations (8c952dc4 sense, 50693752
story, 0e098e7b daily_schedule) but applied via direct generate() rather
than the talent dispatcher: detect_created.md is loaded through
think.prompts.load_prompt, not think.talent.get_talent, so the schema
lives co-located at think/detect_created.schema.json and is passed
explicitly.
Schema uses the provider-intersection subset only (type, enum, pattern,
required, additionalProperties, properties, minLength), with root
additionalProperties: false and required: [day, time, confidence, source,
utc]. The module memoizes the schema at import with a module-level
_SCHEMA constant; a malformed schema fails import loudly.
Caller wiring, parsing, UTC->local conversion, and the return shape are
unchanged. think/models.py validates advisorily via Draft202012Validator
and logs violations; no provider plumbing or caller edits were needed.
Live provider validation deferred: the worktree has no .env and provider
keys are unavailable. Advisory schema_validation will engage on the next
real run against google (primary) and anthropic (backup), matching the
0e098e7b precedent.
Tests: tests/test_detect_created_schema.py adds (1) Draft202012Validator
schema-validity, (2) accept/reject matrix covering each field's
constraint, and (3) a wiring assertion that detect_created() passes
_SCHEMA to generate() via monkeypatched think.models.generate. Existing
tests/test_importer.py mocks are unaffected (they return plain dicts and
bypass the schema path). make ci green.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>