Skip to main content

No. 2

Diagnostics self-read — in-app visibility for the product-events outbox

x-006 ships an in-app diagnostics screen on top of the x-005 telemetry primitive, with self-read endpoints, the durable privacy invariants of the surface, and a gated prod entry-point.

2 min read

x-005 shipped the product-events telemetry primitive: a backend ingest endpoint and a client recordProductEvent({ event, properties }) call. That release deferred the in-app visibility of the outbox to FR-030 and FR-031. x-006 closes both: there is now a self-read API on the backend, a screen on the client that composes the outbox with the server-side history, and the durable contracts of the surface written down so they can be cited.

What x-005 shipped

A working channel: client emits → backend ingests with PII hashing → event lands in the canonical store. See the product-events section for the full doctrine (registry, authoring workflow, PII policy, dashboards).

What x-006 adds

  • Two new self-read endpoints under the account-scoped namespace: GET /api/auth/me/diagnostics/frontend-events (list, paginated by window_hours / limit / event_name) and GET /api/auth/me/diagnostics/frontend-events/{client_event_id} (detail). See the API reference.
  • An in-app diagnostics screen that composes three sources at render time: local outboxes (what the client has emitted but not yet shipped), the new server-side history, and runtime state (request freshness, environment, identity).
  • The durable invariants of the surface, written down: Uniform 404 on detail endpoints, no admin widening for frontend-events, properties payload rendered verbatim on the client.
  • Architecture notes on the non-persistent render path, the useSyncExternalStore cached-snapshot pattern, the 7-tap-version unlock, and resource-policy enumeration: In-app diagnostics surface.

How to reach it (prod)

Open the Account screen and tap the version label seven times within 1500 ms of the first tap. The /diagnostics route opens. The gate is in-memory only — killing and relaunching the app resets the counter. In dev and staging builds the route is reachable directly.

What we did not change

  • Backend perf on the history list endpoints. The backend-operations and frontend-incidents self-read list endpoints observed a 10 s timeout in the x-006 smoke. Investigation is tracked separately; treat list latency as in-progress, not as a production-grade SLO.
  • Client build metadata. Constants.expoConfig.extra.commitSha is not populated by the current build pipeline, so the screen renders for the commit SHA. Follow-up under DevX.
  • PII hashing on the read path. Hashing remains an ingest-time responsibility of the backend; the client renders properties verbatim (see the invariants page for the contract).

Mateus H.

Engineering · canonical layer

Notes from the canonical layer, in your inbox.

Engineering posts and field reports. No spam — unsubscribe in one click.