Session intensity by tier table

What does this MR do and why?

This merge request replaces a placeholder "Session intensity by tier" panel on the AI Impact dashboard with a fully functional one. It introduces a new data source that queries real Duo Agent Platform session data, groups users into four activity tiers (Light, Regular, Heavy, Power) based on how many sessions they ran, and calculates each tier's share of total users and sessions along with an "intensity" ratio showing whether that tier punches above or below its weight in session volume.

Two new reusable table cell components are added to display these values: one that shows a number alongside its percentage of the total, and one that renders plain text with optional bold styling. Both components are wired into the existing data table and validated in the JSON schema. Tests cover the data transformation logic, including tier ordering, share calculations, and the intensity formula.

References

#628035

Screenshots or screen recordings

How to set up and validate locally

Click to expand
  1. Prerequisites: requires a GDK with ClickHouse configured and migrated. The panel reads the duo_workflows_workflows_enriched ClickHouse table, created by migrations dated 2026-08-26 onward: bundle exec rake gitlab:clickhouse:migrate If the table is missing, the panel returns a 500. Check log/exceptions_json.log for a ClickHouse::Client::DatabaseError with Code: 60 ... Unknown table expression identifier.

  2. Enable the feature flags. Both are default-off WIP flags. In rails console: Feature.enable(:explore_analytics_dashboards) Feature.enable(:dap_impact_v1)

  3. Seed ClickHouse. There is no development seeder for this table — in production it's filled by a siphon-fed materialized view that refreshes every 12 hours — so rows need to be inserted directly.

    Two things will silently produce a wrong-looking table rather than an error:

    • traversal_path must be organization-prefixed. 1/33/ is the flightjs group on a default GDK (organization 1, group 33). Confirm your own value with Group.find(33).traversal_path(with_organization: true) in rails console.
    • Every row must be dated inside the dashboard's selected date window (default: Last 30 days). Rows outside it are dropped from the aggregation without an error.

    The inserts use a reserved id range (>= 900000) so cleanup is one statement. Save the SQL below as seed.sql and run it against ClickHouse: curl -s 'http://localhost:8123/?database=gitlab_clickhouse_development' --data-binary @seed.sql

INSERT INTO duo_workflows_workflows_enriched
  (id, user_id, project_id, created_at, updated_at, status, workflow_definition, traversal_path, _version, _watermark)
SELECT 900000 + number, 1000 + intDiv(number, 2), 7, now() - INTERVAL (number % 25) DAY, now(), 4, 'software_development', '1/33/', now(), now()
FROM numbers(24);

INSERT INTO duo_workflows_workflows_enriched
  (id, user_id, project_id, created_at, updated_at, status, workflow_definition, traversal_path, _version, _watermark)
SELECT 910000 + number, 1100 + intDiv(number, 10), 7, now() - INTERVAL (number % 25) DAY, now(), 4, 'software_development', '1/33/', now(), now()
FROM numbers(60);

INSERT INTO duo_workflows_workflows_enriched
  (id, user_id, project_id, created_at, updated_at, status, workflow_definition, traversal_path, _version, _watermark)
SELECT 920000 + number, 1200 + intDiv(number, 40), 7, now() - INTERVAL (number % 25) DAY, now(), 4, 'software_development', '1/33/', now(), now()
FROM numbers(120);

INSERT INTO duo_workflows_workflows_enriched
  (id, user_id, project_id, created_at, updated_at, status, workflow_definition, traversal_path, _version, _watermark)
SELECT 930000 + number, 1300, 7, now() - INTERVAL (number % 25) DAY, now(), 4, 'software_development', '1/33/', now(), now()
FROM numbers(120);

This is 324 flows across 22 users: 12 users with 2 flows each, 6 with 10, 3 with 40, and 1 with 120 — one user landing in each of the four tiers. 4. View the panel. Navigate to /explore/analytics_dashboards/dap_impact. Set the scope picker to the flightjs group. Open the Adoption view (second tab). Scroll to the Session intensity by tier panel. 5. Expected result:

Tier Users Sessions Intensity
Power (100+) 1 4.5% 120 37.0% 8.1×
Heavy (25–99) 3 13.6% 120 37.0% 2.7×
Regular (5–24) 6 27.3% 60 18.5% 0.7×
Light (1–4) 12 54.5% 24 7.4% 0.1×
Check: rows are ordered most-active tier first. In the Users and Sessions columns, the count renders at full size with its share of the total as smaller grey subtext beside it. The Intensity value is bold. Intensity is the tier's share of sessions divided by its share of users, so above 1 means those users each run more sessions than average.
  1. Check the tooltips.
    • Each of the three column headers has an info icon with a description.
    • Hovering the percentage (not the count) in the Users or Sessions column shows the raw numerator and denominator — 1/22 for the Power row's Users, 120/324 for its Sessions.
  2. Exercise the date filter. Change the dashboard date range to Last 7 days. The panel re-queries and the counts drop, since the seeded rows are spread over 25 days. Pick a range with no data and the panel should render empty rather than erroring.
  3. Clean up: ALTER TABLE duo_workflows_workflows_enriched DELETE WHERE id >= 900000;
  4. Automated tests: yarn jest spec/frontend/analytics/analytics_dashboards/components/visualizations/data_table/format_text_spec.js spec/frontend/analytics/analytics_dashboards/components/visualizations/data_table/calculate_percent_of_total_spec.js ee/spec/frontend/analytics/analytics_dashboards/components/data_sources/dap_session_intensity_by_tier_spec.js bundle exec rspec ee/spec/services/analytics/custom_dashboards/system_dashboards_loader_spec.rb The rspec spec loads every shipped system dashboard and drops any that fails JSON schema validation, so it's the guard on the dashboard YAML changes in this MR.
  5. Storybook (optional). The two new table cell components have stories, viewable with yarn storybook:start: format_text and calculate_percent_of_total, both under analytics/analytics_dashboards/components/visualizations/data_table.

MR acceptance checklist

Evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.

Related to #628035

Edited by Alex Pennells

Merge request reports

Loading
Loading