Triage Origin Read Access (2026-07-16)

Decision: Branch-scoped portal users (scheduler/assistant/goa) get read access to JES Triage-account projects whose triage_originating_branch resolves to their own branch. Write endpoints keep the strict linked-account rule.

Why: Branch surfaces deliberately display legacy triage work under its originating branch — the pier log tracker maps triage rows via triage_originating_branch, so JES branch staff see the rows but got 403 opening them. Reported by Zoe Kelley (Manassas assistant) via 9 Gibson Place, Gaithersburg (blkhse.379126); 30 of 50 active tracker rows were affected for Manassas alone.

Implementation: entirely-api 9829c89routes/portal_projects.py:_project_read_denied, built on config.resolve_originating_account plus a local _ACCESS_ORIGIN_FALLBACK for GW origin names (kept out of the shared routing map on purpose — cert/invoice routing must stay JES-scoped). Applied to: project detail, flags, deliveries, sow-validation, quick-search. Side effect: the triage role can now also open triage-account projects through the portal detail endpoints (its account list covers the 6 JES branches but never included the triage holding account itself).

Unchanged: financial redaction for assistant/triage roles (_strip_financials), list-endpoint scoping (branch project lists do NOT gain triage rows), all write endpoints (PATCH project, deliver-cert, site-visits, notes POST).

Tests: tests/test_triage_origin_read_access.py (12 tests).

Related: pier-log-phase-2-cutover, legacy-cert-routing-cutoff