Story 1996: frame-ingest boundary

This closes the last write gap in the Matter Brief chain: Vega can propose a frame, but only pramaan-functions may persist it into business.matter_frames. The agent runtime still has no direct business-schema write path.

What changed

SurfaceChange
POST /app/matters/{matter_id}/frame/ingest Validates Vega's envelope, applies whole-frame freeze and per-field locks, CAS-releases the claimed job, appends a source=agent version, re-renders matter_frame_text, audits, and emits matter_frame.updated.
MatterFrameService.ingest_agent_frame Owns the HR-21 write boundary. Canonical overlap resolution is exact-normalized only; no-match or ambiguous values remain proposed for human ratification.
framer_trigger The AgentCore invoke payload now carries Vega's required input: title, matter type, document summaries, previous frame, and locked fields. The run-input manifest is inserted with one bounded INSERT ... SELECT.
manual_span Adds registry span functions.matter_frame.ingest with firm_id, event.type, and run_id.

Write sequence

Vega FrameOutput
  -> POST /frame/ingest
  -> FrameOutput validation
  -> whole-frame freeze skip
  -> locked_value overlay
  -> exact-normalized canonical markers
  -> generation CAS release on ops.matter_frame_jobs
  -> append business.matter_frames source='agent'
  -> render matters.matter_frame_text
  -> audit actor_kind='agent'
  -> ops.domain_event_outbox matter_frame.updated

Verification

uv run ruff check src/domains/matter_frame src/app_api/router_matters.py src/workers/framer_trigger tests/unit/test_framer_trigger_processor.py tests/integration/test_framer_trigger_jobs.py tests/integration/test_app_matter_frame_write_api.py
uv run mypy src/domains/matter_frame src/workers/framer_trigger --follow-imports=silent --ignore-missing-imports
uv run pytest tests/unit/test_framer_trigger_processor.py -q
set -a; . ./.env.test-db; set +a; uv run pytest tests/integration/test_app_matter_frame_write_api.py -q
set -a; . ./.env.test-db; set +a; uv run pytest tests/integration/test_framer_trigger_jobs.py -q
make openapi