Skip to content

Reporting layer v1: scatter, dual-axis overlay, brush-zoom (#1606) - #1683

Merged
erikdarlingdata merged 2 commits into
devfrom
feature/1606-reporting-layer
Jul 26, 2026
Merged

erikdarlingdata merged 2 commits into
devfrom
feature/1606-reporting-layer

Conversation

@erikdarlingdata

Copy link
Copy Markdown
Owner

The charting item of #1606, re-prioritized: "investment in reporting layer is crucial."

What's new

  • Second measure (overlay) — a panel can carry one more same-source measure. It compiles as a second select expression (AS value2) over the same fact rows — the ratio two-operand precedent generalized: never a join, never a parameter, one query. Same aggregate/unit rulebook as the primary (extracted into a shared helper so the two can't drift); coherence-gated to scatter and ungrouped line/area, rejected everywhere else by name.
  • Scatter — ranked two-measure viz: one point per group, x ranks by the primary, y is the overlay. Hover titles, drill-to-filter clicks, dual nice-scaled axes with unit captions.
  • Dual-axis line/area — an ungrouped time series draws the overlay against its own right-hand axis (own scale/caption, reserved dashed color). The right gutter is reserved only when an overlay is present — existing charts render byte-for-byte unchanged.
  • Brush-zoom — pointer-capture drag on any time-series chart re-RUNS the panel on the brushed absolute window: the auto bucket re-resolves, retention tiers re-route, and the Darling compose: CAGG routing has no rollup-availability gate — old-window custom-view panels throw 42P01 on plain-PostgreSQL stores #1665 partial-window notice stays honest. Zoom chip (with reset) survives empty/error results — a historical zoom can legitimately return one daily bucket.
  • Absolute run windows — /api/compose/run (and therefore MCP run_custom_view_panel) gains windowStart/windowEnd: ISO-8601, precedence over hours, both-or-neither, start<end, 90-day ceiling, reject-not-clamp. Historical analysis becomes first-class.
  • NowUtc decoupling — ComposeRunContext.NowUtc separates "when is now" from "when does the window end": routing and the retention notice measure age from actual now. Pinned: a 30→25-days-ago window routes to the daily rollup.
  • CAGG AND-gate — one route serves both value expressions; if either measure can't remap to the rollup columns the whole panel reads raw.
  • Composer UI: Second-measure picker, scatter in the chart list, all five viz-coherence mirrors updated, and stored definitions round-trip the overlay through edit-and-save. MCP catalog/tool prose updated (also fixes its stale stacked-bar omission).

Design + review

Plan reviewed adversarially by a separate tech-lead agent before implementation; all findings adopted (overlay coherence outside ValidateVizMode's table early-return, editor mirror threading, reject-not-clamp window semantics, zoom-chip-on-empty, param-order invariance pin, pivotTimeSeries value2 wiring, otherColumns exclusion).

Testing

  • 9-case overlay rejection matrix + accept pins (scatter, ratio overlay with fixed aggregation).
  • Compile pins: AS value2, parameter-count invariance with/without overlay, scatter SQL shape (ORDER BY value DESC + bound LIMIT), both-remap-or-raw on the rollup route, historical-window NowUtc routing.
  • 4-case absolute-window rejection matrix (no live store needed — rejects before any round trip).
  • Full suite 3140/0; live-gated against a fresh plain PostgreSQL 17: 3268/0.
  • Post-merge: DARLING01 deploy + demo panels (duration-vs-executions scatter, CPU%+batches dual-axis) for the visual pass.

🤖 Generated with Claude Code

The composer's charting gaps, closed as one coherent model extension:

- overlay (second measure): same-source only, compiled as one more
  select expression over the same fact rows (the ratio two-operand
  precedent generalized) - never a join, never a parameter, one query.
  Validated by the exact aggregate/unit rulebook the primary uses
  (shared ResolveAggregateAndUnit helper), coherence-gated to scatter
  and ungrouped line/area, rejected elsewhere by name.
- scatter viz: ranked, one point per group, x = primary (ORDER BY
  value DESC LIMIT topN), y = overlay's value2; hover titles + drill
  clicks; own renderer with dual nice-scaled axes.
- dual-axis line/area: the overlay drawn against its own right-hand
  axis (own scale, unit caption, reserved color, dashed) - the right
  gutter is reserved only when an overlay is present, so overlay-less
  charts render byte-for-byte as before.
- brush-zoom: pointer-capture drag on any time-series chart re-runs
  the panel on the brushed ABSOLUTE window; run endpoint gains
  windowStart/windowEnd (ISO-8601, precedence over hours, both-or-
  neither, start<end, 90-day ceiling, reject-not-clamp) - historical
  windows become first-class for MCP too. Zoom chip survives empty
  and error results.
- NowUtc decoupled from EndUtc in ComposeRunContext: routing and the
  partial-window notice measure age from actual now, so a zoomed
  30-to-25-days-ago window routes to the daily rollup (pinned).
- CAGG AND-gate: one route serves both value expressions; either
  failing to remap sends the whole panel to raw.
- Composer UI: Second-measure picker, scatter in the chart list, the
  five viz-coherence mirrors updated, overlay round-trips through
  descToComposedPanel/composedPanelToDesc (edit-and-save can never
  silently shed it). MCP catalog/tool prose updated (also fixes the
  stale stacked-bar omission).

Tests: 9-case overlay rejection matrix, accept pins (scatter + ratio
overlay), compile pins (AS value2, param-count invariance, scatter
SQL shape, both-remap-or-raw, historical-window routing), 4-case
absolute-window rejection matrix. Suite 3140/0; live-gated vs fresh
plain PG 3268/0.

Closes the charting item of #1606.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@erikdarlingdata
erikdarlingdata merged commit 07040ab into dev Jul 26, 2026
4 checks passed
@erikdarlingdata
erikdarlingdata deleted the feature/1606-reporting-layer branch July 26, 2026 15:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant