Diagnosis access boundary: detail-free overview, why behind admin gate#

ops-db-ui diagnosis wiring, epic #139. Relates to ADR-0001 (live-check contract) and the data-transfer error-breadcrumb work.

Context#

Two audiences watch the transfer pipeline. Observers (scientists, data-reduction users) cannot act on the system — no tokens, no SSH — but need to know what is stuck where (“did my data leave the site, is my package stuck”). Admins can act and need the why. The new “dive into the diagnosis” UI hangs a Diagnose action off the shown failures; the question is who may see the error_context (paths, hosts, traceback, the Diagnosis line).

The constraint that decides the design: GET /api/transfer/overview and the /ws/overview WebSocket are currently anonymous at the API layer, and the WebSocket broadcasts one shared payload to every connected client. Today that payload embeds each failed operation’s error_context/failure_error_message, so the why is already broadcast to anyone listening.

Decision#

The boundary is structural, not a per-role strip. The overview payload (HTTP and WebSocket) carries no error text for anyone: error_context, failure_error_message, and unpack_error_context are removed from the failed-op entries. What remains is what an Observer needs — package, location pair, stage, status, retry count, ids, timestamps.

The why flows only through the already-admin-gated endpoints (/api/admin/diagnose/{type}/{id}, /api/admin/diagnose/by-package/{name}, failure-history, and the live-check trigger/poll). The UI’s Diagnose action (admin-only via auth/isAdmin) is the single gateway to a Diagnostic Report; there is no inline Diagnosis, even for admins.

Considered options#

  • (a) Detail-free overview (chosen). The overview stays anonymous and broadcastable; the boundary is enforced by where error_context lives (behind the admin gate), not by who is listening. Cost: admins lose the inline breadcrumb in the failure panel and click Diagnose to see the why.

  • (b) Role-aware overview. Authenticate GET /overview and /ws/overview, include error_context for admins, null it otherwise. Rejected: retrofits auth onto a hot anonymous endpoint and a broadcast WebSocket — role-aware stripping over WS needs per-connection filtering or two payload variants, a bug-prone surface for a diagnostic nicety. The leak would also remain one schema change away from reappearing.

Consequences#

  • The inline FailureBreadcrumb rendered inside FailureAlertPanel is removed; the breadcrumb now lives only inside the Diagnose drawer / /admin/diagnose page (OperationDiagnosisRow already renders it).

  • /overview and /ws/overview need no auth changes — the reason this option was chosen.

  • Removing error_context from TransferOverview and its failed-op entries is a payload change; the ops-db-ui consumer must move why-display into the admin-gated Diagnose path in lockstep.

  • The boundary holds only as long as no other anonymous endpoint re-exposes error_context. New failure-surfacing endpoints must keep error text behind the admin gate.