Story-2791 · functions lane · create contract

Matter posture and the represented participant now agree

An adversarial matter cannot enter the backend without naming the participant label for the client-side us party, while an advisory matter cannot carry that adversarial label by mistake.

Why the request is checked as one unit

representingSide and the client-side participant label are individually valid fields, but their combination determines whether the request tells a coherent story. MatterCreateRequest therefore validates the relationship after all parties have been parsed.

representingSide
      │
      ├── adversarial ── requires label id OR label name on role "us"
      │
      └── advisory ───── forbids a label on role "us"

Accepted and rejected combinations

PostureClient-side us labelResult
adversarialparticipantLabelId or participantLabelNameAccepted
adversarialAbsent422: participant label is required
advisoryAbsentAccepted
advisoryPresent422: participant label must not be set

The existing two-value RepresentingSide enum remains unchanged, so legacy values such as principal and opposing are still rejected.

Acceptance evidence

Negative pathsFocused DTO tests reject adversarial requests without a client label and advisory requests with one.
Happy pathsTests accept adversarial labels supplied by either identifier or name, plus advisory requests with no client label.
Existing create coverageAdversarial route, service, contract-fixture, and team fixtures now provide an explicit labeled us party.
Red-first proofBoth negative tests were observed failing before the model validator was added.

Scope and staging sequence

This Story changes only the create request DTO, focused validation tests, and existing test fixtures. It adds no migration and no service or persistence behavior; persistence remains owned by Story-2792.

The client UI support is delivered by app Stories #2794 and #2795. Until those land, app-driven adversarial matter creation returns 422. This temporary staging sequence is accepted because there are no real clients.

Governing issue: pramaan-spec#2791.