representing_side orientation inputMatter Significance / the comparator reads a document as helpful-vs-hurtful only
if it knows which side our counsel acts for. Spike-2628 found that input missing:
declared_side already exists per-document (migration 0151, whose document
this is), but representing_side — the matter's own position — was absent
everywhere in functions. Without it the comparator has nothing to orient against. This
story lands the field so the matter captures it permanently at creation; it does
not build the comparator's consumption of it (that layer is not built yet).
representing_side is a three-value closed enum stored on the matter:
| Value | Meaning |
|---|---|
principal | We act for the principal adversarial side — Claimant / Plaintiff / Petitioner / Complainant, derived by forum. |
opposing | We act for the opposing side — Respondent / Defendant / Accused. |
advisory | No single adverse side — mediation, advisory, multi-party, in-house. The comparator runs neutral in this mode. |
Only representing_side is stored. The adversary label is derived at
render from this value plus the forum (via the app's forumAwareRoleLabel()) —
never duplicated onto participant rows, because two stored copies drift. And
advisory is a required, first-class value: not every matter is a clean
two-sided fight, so the field must let counsel say "no single adverse side" rather than
force a false for/against. That is the same honesty rule as pramaan-docs ADR-175 — the
comparator must never manufacture an orientation that does not exist.
add matters.representing_side (nullable)
│
▼
UPDATE business.matters SET representing_side = 'principal' -- every existing row
│
▼
ALTER … SET NOT NULL, server_default 'principal', + CHECK IN (principal, opposing, advisory)
│
▼
COMMENT ON COLUMN … -- byte-identical to the model, so `alembic check` stays clean
The backfill sweeps all existing matters to principal in the same
migration. Rationale: staging is dummy data — no clients, no production — so a clean sweep
is safe, and principal is the modal real case, giving the comparator a testable
orientation. Real matters set the value explicitly at creation going forward. The
NOT NULL plus 'principal' server_default is a staging safety net for
direct inserts; the create DTO still requires an explicit value, so the API boundary never
silently defaults a real matter. Downgrade drops the CHECK and the column.
| Surface | Change |
|---|---|
RepresentingSide StrEnum | New, in src/shared/constants/firm_status.py. |
MatterCreateRequest | representing_side required — validated against the closed enum, so an omitted or unknown value is a 422. |
| Read DTO | Present on MatterListItem (inherited by MatterDetailView) so the app can display it. |
| OpenAPI | openapi/app-api.json regenerated so pramaan-app can codegen the new field. admin-api.json unaffected — the matter DTO does not surface there. |
Producer only: this ticket makes the field exist and be captured. The pramaan-app
matter-creation UI and the comparator both consume the contract in later, separate tickets.
The per-document declared_side split is preserved untouched (sibling of Epic-2624 /
Indigo).
The matter stores one orientation fact — principal, opposing, or advisory — the adversary is derived not duplicated, advisory is always available so no fight is faked, and every existing dummy matter starts at principal.