Story-1998 functions lane Matter Frame

Matter Frame counsel edit, lock, and ratify API

Story-1998 turns the persisted Matter Frame into something counsel can safely correct, protect, accept, or reject without letting a later Vega pass overwrite counsel judgment.

The mental model: the Matter Frame is an append-only ledger. An edit writes a new page, a lock pins one field on the desk, and ratify decides whether a proposed value becomes counsel-owned truth or a suppressed proposal.

What changed

Counsel edit

PATCH /app/matters/{matter_id}/frame appends a new source='counsel' version and refreshes the derived matter_frame_text.

Field lock

PUT and DELETE on /frame/locks/{field} maintain business.matter_frame_field_locks with the pinned locked_value.

Ratify

accept locks the proposed value as counsel-owned. reject clears the field and pins the cleared value so Vega does not re-propose it.

Canonical handoff

Some frame fields are mirrors of canonical product state. Accepting tribunal_name or forum_type writes the Main proceeding's forum through the existing proceeding command path. Accepting parties creates a matter participant through the existing matter identity command path.

That is the ownership transfer: once counsel accepts a proposal, the canonical table owns the durable record and the frame keeps the counsel decision in its envelope and lock row.

Safety rails

  1. Every command resolves the matter through the firm-scoped app service path, so RLS remains the tenant boundary.
  2. Every frame write appends a matter_frames version; no prior version is mutated.
  3. Every command emits audit activity, and appended versions enqueue matter_frame.updated through the domain-event outbox.
  4. The integration tests call the real app routes against a freshly migrated test database, including lock refresh, canonical forum transfer, participant creation, and rejection suppression.

Verification: uv run ruff check, uv run mypy, route-level pytest, full pytest, and make openapi are the intended PR checks for this Story.