Found by live verification of #118.
Splitting Report.Gates into Gates and Events (#121) reached /stats and Prometheus but not the dashboard's per-request surface:
dash/event.go:504 — row.Gates = r.Gates, with no events counterpart.
dash/schema.go:585 — the component row has only a gates column.
So sweep_dropped, sweep_offered, sweep_candidate_at_depth, reapplied_same_session and the other seven migrated names are absent from the per-request component row — which is the surface docs/hosted.md points operators to for "what did this component do on this request".
The aggregate views are fine: /stats carries both maps and Prometheus exports cg_component_events_total{component,event}. It is the per-request drill-down that lost them, and that is the one used to explain a single turn.
Why this is worse for the components that work
The names that moved are the ones a component raises when it succeeds. So the drill-down is now blind in proportion to how well a component is doing: a turn that removed twelve outputs and saved 33,340 tokens shows an empty gates cell, while a turn that refused everything shows a full one. Verified live during #118's re-verification.
The sibling defect on the log line (apply.logDecisions rendering only rep.Gates) is fixed in #118 — same root cause, and that one was three lines. This one is not: it needs a column, a schema migration, the API shape, and the UI, so it was flagged rather than bundled into an unrelated PR.
Worth deciding while you are there
Whether the row keeps two columns or one with a type discriminator. Two columns matches /stats and Prometheus and keeps the two questions visibly separate, which is the whole reason for the split; one column plus a flag is a smaller migration but re-creates the ambiguity at the storage layer that #121 removed at the metrics layer.
Found by live verification of #118.
Splitting
Report.GatesintoGatesandEvents(#121) reached/statsand Prometheus but not the dashboard's per-request surface:dash/event.go:504—row.Gates = r.Gates, with no events counterpart.dash/schema.go:585— the component row has only agatescolumn.So
sweep_dropped,sweep_offered,sweep_candidate_at_depth,reapplied_same_sessionand the other seven migrated names are absent from the per-request component row — which is the surfacedocs/hosted.mdpoints operators to for "what did this component do on this request".The aggregate views are fine:
/statscarries both maps and Prometheus exportscg_component_events_total{component,event}. It is the per-request drill-down that lost them, and that is the one used to explain a single turn.Why this is worse for the components that work
The names that moved are the ones a component raises when it succeeds. So the drill-down is now blind in proportion to how well a component is doing: a turn that removed twelve outputs and saved 33,340 tokens shows an empty gates cell, while a turn that refused everything shows a full one. Verified live during #118's re-verification.
The sibling defect on the log line (
apply.logDecisionsrendering onlyrep.Gates) is fixed in #118 — same root cause, and that one was three lines. This one is not: it needs a column, a schema migration, the API shape, and the UI, so it was flagged rather than bundled into an unrelated PR.Worth deciding while you are there
Whether the row keeps two columns or one with a type discriminator. Two columns matches
/statsand Prometheus and keeps the two questions visibly separate, which is the whole reason for the split; one column plus a flag is a smaller migration but re-creates the ambiguity at the storage layer that #121 removed at the metrics layer.