tallyman is building a per-project activity/perf log and wants a timeline of a single grid load, but most of that pipeline is invisible outside buckaroo. The companion (tallyman) only sees the first browser request and its own /load_expr POST; everything after — summary-stats compute, whether the stat cache was hit, and the WebSocket row-range requests between the browser and the buckaroo server — happens inside buckaroo's server and the buckaroo-js-core widget. The row traffic flows browser ↔ server directly over the WS and never reaches the companion, so tallyman is structurally blind to it.
Proposal: instrument the buckaroo server and packages/buckaroo-js-core (widget) to emit OpenTelemetry spans for one grid load, correlated by the buckaroo session id, so a consumer (tallyman, or a Jaeger/Tempo backend) can render the waterfall.
Trace model
One trace per grid load, correlation keyed on the session id minted at /load_expr. Spans:
load_expr (server) — POST received → build/replay ready. Continue trace context injected by the caller (tallyman puts it on the POST headers).
summary_stats (server) — start/end, attributes cache_hit: bool, cache_path, n_columns, n_stats. (tallyman passes the stat-cache path but never learns hit/miss — only the server knows.)
row_range (server) — one span per row-range request received over the WS: received_at, replied_at, start, end, n_rows, served-from-row-cache.
row_request / first_paint (widget, buckaroo-js-core) — the browser side: when the widget issues its first row request and receives the first rows, plus subsequent requests. Continue the trace over the WS handshake.
Emission / propagation
- Server:
opentelemetry-sdk + an OTLP exporter (env-configurable endpoint); accept/continue trace context on the /load_expr POST and on the WS connect.
- Widget:
@opentelemetry/api + a web exporter; propagate context on the WS messages.
- Ingestion (tallyman side, decided at integration): (a) a custom OTLP→
events.jsonl exporter in the companion so spans land in tallyman's Log UI, and/or (b) a standard collector (Tempo/Jaeger) for the waterfall.
Why this lives here, not in tallyman
The companion is structurally blind to the WS row traffic and to buckaroo's internal stat compute. Only the server and the widget observe these timings. tallyman captures the request→load_expr slice on its own side (Phase 1, tracked in the tallyman repo).
Context
Split out from tallyman's project-activity-log work: Phase 1 (in tallyman) lands the discrete event log (MCP build success/failure, alias creation, Buckaroo grid-load failures) plus the companion-visible load_expr timing. This issue is Phase 2 — the in-buckaroo pipeline timing. Touches the same /load_expr/session surface as #925 (per-session RSS) and #930 (JS backend).
tallyman is building a per-project activity/perf log and wants a timeline of a single grid load, but most of that pipeline is invisible outside buckaroo. The companion (tallyman) only sees the first browser request and its own
/load_exprPOST; everything after — summary-stats compute, whether the stat cache was hit, and the WebSocket row-range requests between the browser and the buckaroo server — happens inside buckaroo's server and thebuckaroo-js-corewidget. The row traffic flows browser ↔ server directly over the WS and never reaches the companion, so tallyman is structurally blind to it.Proposal: instrument the buckaroo server and
packages/buckaroo-js-core(widget) to emit OpenTelemetry spans for one grid load, correlated by the buckaroo session id, so a consumer (tallyman, or a Jaeger/Tempo backend) can render the waterfall.Trace model
One trace per grid load, correlation keyed on the session id minted at
/load_expr. Spans:load_expr(server) — POST received → build/replay ready. Continue trace context injected by the caller (tallyman puts it on the POST headers).summary_stats(server) — start/end, attributescache_hit: bool,cache_path,n_columns,n_stats. (tallyman passes the stat-cache path but never learns hit/miss — only the server knows.)row_range(server) — one span per row-range request received over the WS:received_at,replied_at,start,end,n_rows, served-from-row-cache.row_request/first_paint(widget, buckaroo-js-core) — the browser side: when the widget issues its first row request and receives the first rows, plus subsequent requests. Continue the trace over the WS handshake.Emission / propagation
opentelemetry-sdk+ an OTLP exporter (env-configurable endpoint); accept/continue trace context on the/load_exprPOST and on the WS connect.@opentelemetry/api+ a web exporter; propagate context on the WS messages.events.jsonlexporter in the companion so spans land in tallyman's Log UI, and/or (b) a standard collector (Tempo/Jaeger) for the waterfall.Why this lives here, not in tallyman
The companion is structurally blind to the WS row traffic and to buckaroo's internal stat compute. Only the server and the widget observe these timings. tallyman captures the request→
load_exprslice on its own side (Phase 1, tracked in the tallyman repo).Context
Split out from tallyman's project-activity-log work: Phase 1 (in tallyman) lands the discrete event log (MCP build success/failure, alias creation, Buckaroo grid-load failures) plus the companion-visible
load_exprtiming. This issue is Phase 2 — the in-buckaroo pipeline timing. Touches the same/load_expr/session surface as #925 (per-session RSS) and #930 (JS backend).