dotCMS / dotCMS/core

Experiments Portlet — Screen 3: View Results

Open
#37,004 1 comment 0 reactions 1 assignee View on GitHub

@erickgonzalez is already working on this.

Since Sep 8, 2026.

dotCMS : Experiments Team : Falcon Type : New Functionality
Dominant language
Java
Stars
970
Forks
486
Avg merge
3d 33m
Merged PRs (30d)
170

Description

Description

The Results screen on the portlet's stack: stat strip, Daily/Bayesian tabs, summary table, promote. The current reports screen is the cheapest to port — its store is already page-independent (state is only {experiment, status, results}, loaded by experimentId alone) — but it is rewritten on Signal Store Events like the rest of the portlet, and the charts/data plumbing are reused, not reinvented.

Heads-up before starting: experiment results still go through CubeJSClient on main (2 CubeJS round-trips + a 1000-sample Monte Carlo per call, @NoCache) — #36763 Part 1 migrates that to CAEM + ClickHouse. Confirm with the analytics team whether to build against the current contract or wait for the new one; the result model (ExperimentResults, GoalResults, VariantResults) is unchanged by the migration, so building now is expected to be safe.

Design: approved prototype, results screen.

Scope
  • Route: /experiments/:experimentId/results (placeholder wired by #36989).
  • Header: back to the list · name + status tag · subline {pageTitle} · {pagePath} · {n} Variants · Configuration button (→ #37003's screen) · Stop Experiment when RUNNING.
  • Stat strip: Winner (ENDED) / Leading Variant (otherwise) with inline Promote when the leader is not the control · Goal name · Period · Sessions To Date. Ported: "no winner yet" negative state (block icon + legend — the design has no negative state) and the refresh-results button (results are @NoCache; users watch this screen while the test runs).
  • Tabs: Daily Results (conversion rate by day, one series per variant, interactive legend) · Bayesian Results (posterior distribution). Reuse the existing Chart.js setup (dot-experiments-reports-chart/chartjs/ chart options) — do not hand-roll the prototype's SVG. Bayesian summary data comes from the backend (bayesianResult in the results payload): conversion rate, credibility interval, probability and risk per variant. The posterior curve is sampled on the client. BayesianResult.distributionPdfs can supply it, but it is gated behind INCLUDE_BETA_DISTRIBUTION_SAMPLES (off by default) and carries BETA_DISTRIBUTION_SAMPLE_SIZE points per variant — a thousand out of the box — on an endpoint that is @NoCache. Sampling a Beta locally costs less than putting those points on the wire on every read.
  • Summary table (under both tabs): Variant (dot, name, CONTROL/LEADING chips) · Sessions · Conversions · Conversion Rate · Lift vs Original (percentage points, +11.7 pts, green/red, on control — the one design addition over the current table) · Probability To Be Best · Conversion Rate Range (95%) · Promote. Ported: minimum-10-sessions gate (below it, empty state instead of meaningless rates) and promoted state (Promote buttons hidden once a variant is promoted; a variant must not be promotable twice).
  • Promote confirm: promoting while RUNNING auto-ends the experiment (ExperimentsAPIImpl.java:1392) — the confirm must say so; the design draws a bare button.
  • Analytics health gate on this route only: reuse dotAnalyticsHealthCheckResolver from @dotcms/ui (not the edit-page-coupled AnalyticsAppGuard). The list must not be gated.
  • Store: Signal Store Events (experiments-results.events.ts), load/refresh/promote as Request → Succeeded → Failed triples.
  • Unhide from Screen 1: the View Results primary row action in #36989 routes here.

Acceptance Criteria

  • /experiments/:id/results renders stat strip, tabs and summary per the design for RUNNING and ENDED experiments.
  • Daily and Bayesian charts render with the existing Chart.js config; legend toggles series.
  • Lift vs Original shows points vs the control row, green/red, on control.
  • Below 10 sessions the summary shows the empty state.
  • Refresh re-fetches results without a full navigation.
  • No suggested winner → the negative state renders, not a false "Leading Variant".
  • Promote asks confirmation; RUNNING copy states the experiment will be ended; after promoting, Promote buttons disappear and the promoted row is marked.
  • A misconfigured analytics app blocks only this route, not the list.
  • The old UVE reports screen is untouched.
  • Jest specs for the results store and summary table.

Priority

Medium — independent of #37003; can run in parallel once #36989's shell exists.

Additional Context

  • Depends on: #36989. Independent of #37003.
  • Out of scope: any change to the results backend contract; charts in the list; bayesHeadline/bayesNote narrative copy (present in prototype logic, unrendered — confirmed dropped).
  • Port sources: dot-experiments-reports/ (store shape dot-experiments-reports-store.ts:51-55,208, summary, details table, chartjs/).
  • E2E (empty state, 10-session gate, promote confirm) lives in the dedicated E2E issue.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.