the current hard validation requiring Fee % to sum to exactly 100% is blocking us from making any edits or adding new law firms. even with Law Firm Admin and Tekmir Admin permissions, the system triggers a "Failed to update law firm" error because the total doesn't hit 100% mid-edit.
The hard sum-to-100 validation QA describes does not actually exist in the
code. PR #2422 explicitly ships the sum-of-fees as a soft amber/green warning
(see getFeeAllocationWarning in law-firm-role-form-utils.ts), and there
are no sum-100 checks in the zod form schema, the Pydantic request models,
the route handlers, or DB constraints.
The error QA actually saw is HTTP 403 Forbidden from the new
POST /v2/matters/{id}/roles and PATCH /v2/matters/{id}/roles/{role_id}
endpoints. PR #2422 introduced a _require_matter_write_access helper on
those two routes that resolves the public user, computes entitlements from
public.users.roles, and rejects with 403 if matter:write is missing.
The test environment uses the ?assume_roles=... cookie (and the Debug
popover that sets the same cookie) to flip UI gates so write affordances
appear. That cookie is read only by the Next.js UI — it does not change
public.users.roles and therefore does not affect the backend's
_require_matter_write_access decision.
Net effect for QA:
?assume_roles=Tekmir Adminmakes the Add Law Firm button and Edit pencil visible.- Save Changes triggers PATCH; the backend's entitlement check sees no
matter:writeon the user's actual roles → 403. - The UI surfaces the failure as the generic "Failed to update law firm"
inline error, rendered next to the orange
Total fee allocation across all firms is X% (under 100%)warning. - The two messages co-occur, so the failure appears to be caused by the sum-not-100 warning. It is not.
Other v2 write endpoints in api-hub do not run a server-side
matter:write check. They rely on UI gates (<Gate entitlement="matter:write"> / useHasEntitlement) and let the request
through at the API layer if it arrives. PR #2422 made the new role
endpoints stricter than the rest of the surface — the only routes in this
file with the helper are the two added by that PR.
So assume_roles testing flows that previously worked everywhere else
(edit matter, edit contact, etc.) fail uniquely on these two endpoints,
which made the bug look like it was about the new dialog or the warning
text.
Drop the server-side entitlement check on the two new endpoints to match
the rest of the v2 surface. UI gating via <Gate entitlement="matter:write">
remains the single layer of protection, consistent with sibling endpoints.
Removed:
_require_matter_write_accesshelper incase_management_pipeline/projects/api-hub/api_hub/api/v2/routes/matter.py.- Both
await _require_matter_write_access(request, db)call sites insidecreate_matter_law_firm_roleandupdate_matter_law_firm_role, along with the now-unusedrequest: Requestparam on each. - The four imports the helper relied on (
get_entitlements_for_roles,Entitlement,resolve_or_bootstrap_current_public_user,UserDatabaseRepository). test_create_matter_law_firm_role_rejects_read_only_userintegration test — its 403 assertion no longer applies.
Server-side enforcement of matter:write across all v2 write endpoints is a
larger consistency project that should land separately, not bundled into a
hotfix.
- Branch:
alexlazarian/clu-470-hotfix-1offmain - Matter: PFAS Huels (
f6ec4859-714f-4222-93fa-f1f5f2015013, seeded bymake db-reset) - URL:
/matters/f6ec4859-714f-4222-93fa-f1f5f2015013/firms - Steps:
- Open Edit Law Firm dialog on D&C
- Change Fee Percentage
0.15→0.10(total becomes 95%) - Click Save Changes
- Observed before fix (with
public.users.roles = '{}'): PATCH 403, "Failed to update law firm" inline error rendered next to the orange "(under 100%)" warning.
Same matter, public.users.roles = '{}', Fee 0.15 → 0.20 (total 105%):
PATCH returns 200 OK, row updates to 20.0%, panel re-renders. No 403, no
"Failed to update law firm".

