feat(engineering-analytics): add workflow run activity chart endpoint#67256
Conversation
The workflow run-activity chart reused the runs-list endpoint, which is capped at 200 rows newest-first. On busy workflows those 200 runs all fall within the last day, so the chart's focus-lens brush — gated on the loaded runs spanning more than 24h — never appeared, and the chart stopped well short of the selected date window. Add a dedicated `workflow_run_activity` endpoint that returns a compact per-run projection (start / duration / conclusion / branch / PR) over the full date_from/date_to window at a higher cap (2000), and point the chart at it. The runs table keeps its own 200-row endpoint, so the two reads stay disjoint rather than the chart re-fetching the table's full-detail rows. `truncated` now reflects the chart's own cap. Generated frontend types (api.ts / api.schemas.ts / api.zod.schemas.ts) mirror the Orval output for the new endpoint; run `hogli build:openapi` on a full env to canonicalize. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019Yp2qw9YU7y78eAeEpKmFP
MCP UI Apps size report
|
|
Reviews (1): Last reviewed commit: "fix(engineering-analytics): span run-act..." | Re-trigger Greptile |
Note the run-activity cap's relationship to the run-detail table cap so it doesn't bitrot if the table cap changes. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019Yp2qw9YU7y78eAeEpKmFP
🟢 Eager graphHow much code each root ships on the eager path — downloaded and parsed before the surface is interactive. Measured from the esbuild output chunks (post-tree-shake, static imports only); lazy
🟢 Largest files eagerly reachable from
|
| Size | File |
|---|---|
| 275.0 KiB | ../node_modules/.pnpm/posthog-js@1.396.3/node_modules/posthog-js/dist/rrweb.js |
| 266.9 KiB | ../node_modules/.pnpm/@posthog+icons@0.37.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@posthog/icons/dist/posthog-icons.es.js |
| 223.9 KiB | src/taxonomy/core-filter-definitions-by-group.json |
| 211.0 KiB | ../node_modules/.pnpm/posthog-js@1.396.3/node_modules/posthog-js/dist/module.js |
| 126.8 KiB | ../node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.production.min.js |
| 105.9 KiB | src/lib/api.ts |
| 69.7 KiB | src/products.tsx |
| 61.7 KiB | src/lib/lemon-ui/icons/icons.tsx |
| 57.5 KiB | src/lib/utils/eventUsageLogic.ts |
| 39.6 KiB | src/lib/KeaDevTools.tsx |
Largest files eagerly reachable from src/scenes/AuthenticatedShell.tsx
| Size | File |
|---|---|
| 458.3 KiB | ../node_modules/.pnpm/@posthog+brand@0.3.0_react@18.3.1/node_modules/@posthog/brand/dist/generated/hoggies/svg/driving-hogzilla.mjs |
| 302.9 KiB | ../node_modules/.pnpm/@posthog+brand@0.3.0_react@18.3.1/node_modules/@posthog/brand/dist/generated/hoggies/svg/coffee-run.mjs |
| 275.0 KiB | ../node_modules/.pnpm/posthog-js@1.396.3/node_modules/posthog-js/dist/rrweb.js |
| 266.9 KiB | ../node_modules/.pnpm/@posthog+icons@0.37.4_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@posthog/icons/dist/posthog-icons.es.js |
| 253.2 KiB | ../node_modules/.pnpm/@posthog+brand@0.3.0_react@18.3.1/node_modules/@posthog/brand/dist/generated/hoggies/svg/chart-hog.mjs |
| 239.2 KiB | ../node_modules/.pnpm/@posthog+brand@0.3.0_react@18.3.1/node_modules/@posthog/brand/dist/generated/hoggies/svg/x-ray.mjs |
| 223.9 KiB | src/taxonomy/core-filter-definitions-by-group.json |
| 211.6 KiB | ../node_modules/.pnpm/@posthog+brand@0.3.0_react@18.3.1/node_modules/@posthog/brand/dist/generated/hoggies/svg/money.mjs |
| 211.0 KiB | ../node_modules/.pnpm/posthog-js@1.396.3/node_modules/posthog-js/dist/module.js |
| 185.9 KiB | ../node_modules/.pnpm/@posthog+brand@0.3.0_react@18.3.1/node_modules/@posthog/brand/dist/generated/hoggies/svg/hogpatch.mjs |
Posted automatically by check-eager-graph · sizes are eager output bytes (shipped, post-tree-shake) from the esbuild metafile · part of #32479
|
Reviews (2): Last reviewed commit: "chore(engineering-analytics): document r..." | Re-trigger Greptile |
There was a problem hiding this comment.
Pull request overview
Adds a dedicated, higher-capped backend endpoint for the workflow run-activity chart (to avoid the 200-row cap of the workflow runs detail table), wires it through the engineering analytics facade/presentation layers, and updates the product frontend to load and render the new compact activity dataset.
Changes:
- Backend: introduce
workflow_run_activityquery + contracts + facade API + DRF action + serializers, with atruncatedflag and 2000-run cap. - Frontend: load
workflow_run_activitydata inworkflowRunsLogicand pass it toRunActivityChart(plus regenerate API clients/types). - Tests: add a unit test covering projection, windowing, ordering, and truncation behavior.
Reviewed changes
Copilot reviewed 11 out of 14 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| products/engineering_analytics/mcp/tools.yaml | Adds MCP tool entry for the new workflow run activity operation. |
| products/engineering_analytics/frontend/scenes/WorkflowRunsScene.tsx | Switches the activity chart to consume the new activity endpoint’s data. |
| products/engineering_analytics/frontend/scenes/workflowRunsLogic.ts | Adds loader + selectors for activity runs and truncation state. |
| products/engineering_analytics/frontend/generated/api.zod.schemas.ts | Regenerated Zod schemas to include workflow run activity types. |
| products/engineering_analytics/frontend/generated/api.ts | Regenerated API client function for engineeringAnalyticsWorkflowRunActivity. |
| products/engineering_analytics/frontend/generated/api.schemas.ts | Regenerated TypeScript interfaces + params for the new endpoint. |
| products/engineering_analytics/backend/tests/test_logic.py | Adds coverage for the new activity endpoint behavior via facade API. |
| products/engineering_analytics/backend/presentation/views.py | Adds DRF workflow_run_activity action with schema annotations. |
| products/engineering_analytics/backend/presentation/serializers.py | Adds serializers for activity response + point shape (DataclassSerializer). |
| products/engineering_analytics/backend/logic/queries/workflow_run_activity.py | New curated query returning compact per-run chart points with truncation. |
| products/engineering_analytics/backend/logic/init.py | Adds build_workflow_run_activity builder for parsing and query orchestration. |
| products/engineering_analytics/backend/facade/contracts.py | Adds contract dataclasses for activity points + response envelope. |
| products/engineering_analytics/backend/facade/api.py | Adds facade API entrypoint get_workflow_run_activity with auth support. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
Size Change: 0 B Total Size: 69.8 MB ℹ️ View Unchanged
|
There was a problem hiding this comment.
The PR exceeded the size gate ceiling and has an unresolved substantive comment: the query silently drops rows with NULL run_started_at (via >= date_from), but the contract and serializer declare that field as nullable — creating a misleading API contract. The author should either tighten the contract to non-null and document that runs without timestamps are excluded, or add explicit NULL handling in the WHERE clause.
The workflow_run_activity window filter (`run_started_at >= date_from`) excludes runs whose start timestamp didn't parse, so the endpoint never returns a null start — but the contract/serializer declared it nullable, a misleading API shape flagged in review. Tighten the contract to non-null and document that unparseable-start runs are excluded, since they can't be placed on the chart's time axis. This diverges intentionally from the shared WorkflowRunDetail shape, which lists all runs including queued ones. Generated types will be regenerated by CI's OpenAPI job to match. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019Yp2qw9YU7y78eAeEpKmFP
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: af97658278
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
👋 Visual changes detected for this PR. Review and approve in PostHog Visual Review If these changes are unexpected, they may be caused by a flaky test or a broken snapshot on master. Don't approve — rerun the job or wait for a fix. |
Resolve conflicts in test_logic.py (keep both the activity-chart and the new branch-filter tests) and workflowRunsLogic.ts (window listener comment). The activity endpoint isn't branch-scoped, so it stays off the branch reload. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019Yp2qw9YU7y78eAeEpKmFP
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: abf4228d21
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…branch Master's branch filter scopes the runs table and runner-cost calls via head_branch, but the new activity-chart endpoint didn't take a branch param and wasn't reloaded on setAppliedBranch — so a branch-scoped view plotted every branch's runs under the selected-branch filter. Thread `branch` through workflow_run_activity (query WHERE head_branch, facade, logic, view param) mirroring workflow_runs/workflow_runner_costs, and reload the chart on setAppliedBranch. Extends the branch-filter test to cover the activity endpoint. Generated types canonicalize via CI's OpenAPI job. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019Yp2qw9YU7y78eAeEpKmFP
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 27b80d34fd
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
|
||
| afterMount(({ actions }) => { | ||
| actions.loadRuns() | ||
| actions.loadRunActivity() |
There was a problem hiding this comment.
Mock the activity loader in workflowRunsLogic tests
When this logic is mounted by the existing products/engineering_analytics/frontend/scenes/workflowRunsLogic.test.ts, this new mount-time request now calls engineeringAnalyticsWorkflowRunActivity, but that test's jest.mock('../generated/api', ...) still only provides the runs, runner-cost, and jobs functions. In the Jest environment the imported activity function is therefore undefined, so mounting the logic invokes an undefined loader and dispatches a failure/throws instead of the expected successful load; please add the new API mock/default resolved value and include it in the reload expectations.
Useful? React with 👍 / 👎.
…gic test Master's new workflowRunsLogic test mocks ../generated/api with only the runs/runner-cost/jobs functions; the activity loader this PR added is now called on mount and on branch change, so the mock returned undefined and the loader threw. Add the activity mock + resolved value, include it in the reload expectations, and assert the activity request is branch-scoped too. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019Yp2qw9YU7y78eAeEpKmFP
Problem
The workflow runs detail table is capped at 200 runs, which on busy workflows collapses to a sub-day slice and prevents the run-activity chart from spanning the full window or showing its focus-lens brush. The chart needs a separate, higher-capped endpoint that returns only the minimal fields it plots (start time, duration, conclusion, branch, PR number) without the per-row overhead of the full detail shape.
Changes
Added a new
workflow_run_activityendpoint that serves compact per-run points for a single workflow over a window:Backend:
query_workflow_run_activityinworkflow_run_activity.pythat fetches runs with a 2000-run cap (vs. 200 for the detail table) and projects only the fields the chart needsWorkflowRunActivityPointandWorkflowRunActivityincontracts.pybuild_workflow_run_activityinlogic/__init__.pythat handles date parsing and repo splittingget_workflow_run_activityinfacade/api.pywith authorization supportworkflow_run_activityinviews.pywith OpenAPI schema and parameter validationWorkflowRunActivityPointSerializerandWorkflowRunActivitySerializerinserializers.pyFrontend:
hogli build:openapiworkflowRunsLogic.tsthat loads activity data and maps it to the chart's shape (activityRuns,activityTruncated)WorkflowRunsScene.tsxto pass activity data to the chart componentThe endpoint returns an explicit
truncatedflag so the chart can label itself honestly when the cap is hit — covering only the most recent runs rather than the full window.How did you test this code?
Added unit test
test_workflow_run_activity_projects_and_windowsthat verifies:Existing tests pass. Generated types and API client via
hogli build:openapi.https://claude.ai/code/session_019Yp2qw9YU7y78eAeEpKmFP