observe/extract: schema-constrain frame-id selection
This is the first observe-pipeline structured-outputs migration, using the same direct-caller schema pattern as think/detect_created.py. It adds tests/test_extract_schema.py covering schema validity, accept-reject behavior, and wiring the schema through to think.models.generate.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>