fix(analytics): resync the hand-written types with what the API returns - #3818
blarghmatey wants to merge 1 commit into
Conversation
`frontends/api/src/analytics/types.ts` mirrors ol-analytics-api's response models by hand, and has fallen behind them twice over. The `*_pk` fields are typed `number` and have never been numeric. They are dbt surrogate keys — `dbt_utils.generate_surrogate_key` MD5-hashes its inputs into a 32-character hex string. ol-analytics-api#29 fixed the same mistake server-side, where it was not cosmetic: `ContractUtilization`, `EnrollmentCompletionFunnel` and `ProgramFunnel` were 500ing in production on a Pydantic `int_parsing` error (Sentry OL-ANALYTICS-API-J, 120 events in two minutes). Nothing breaks on this side because every use is a React key, a Map key or Set membership, all of which behave the same for strings — but the `Map<number, …>` in CoursePerformanceTable was only well-typed because the type it read was wrong. Separately, ol-analytics-api#33 moved the activity totals onto the cohort that produced them: a total is now suppressed when few enough learners are behind it, so `total_videos_watched` and its two siblings return null even when the total itself is large. Those three were still typed non-null here, and the five cohort counts the change added (`enrolling_learners`, `certified_learners`, `video_watchers`, `problem_attempters`, `chatbot_users`) were missing entirely, as were `video_watchers`/`problem_attempters` on `ContentEngagementDepth`. Nothing renders wrong today: EngagementTrendChart plots only `new_enrollments` and `certificates_earned`, both already nullable and already handled. The factories were the live hazard — they built fixtures with numeric pks, so every test asserting on one was agreeing with a shape production does not send. Fields were checked against `models.py` on ol-analytics-api@main rather than against the ticket, and deliberately stop there: `contract_id` and the contract-grained models arrive with ol-analytics-api#34, which has not merged. This is the third hand-chase (see also the sso_organization_id shim). ol-analytics-api#37 now publishes an OpenAPI spec per tenant and the generated TypeScript client typechecks clean against it, so this file is on its way out — once the clients repo and the Concourse PIPELINE_CONFIGS entry land, types.ts, clients.ts and the `./analytics-types` export all go with it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AVSXwars1LvgtqV1YWhrB1
OpenAPI ChangesNo changes detected Unexpected changes? Ensure your branch is up-to-date with |
There was a problem hiding this comment.
Pull request overview
Synchronizes analytics frontend types and fixtures with the deployed API models.
Changes:
- Corrects surrogate-key types from numbers to strings.
- Adds missing cohort fields and nullable activity totals.
- Updates related factories, grouping, and tests.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
AnalyticsContent.test.tsx |
Updates course-run test keys to strings. |
CoursePerformanceTable.tsx |
Uses string contract keys for grouping. |
types.ts |
Aligns response types with API models. |
factories.ts |
Generates representative keys and complete fixtures. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
|
|
|
Superseded — #3773 (merged 2026-08-31) already landed this exact fix on Closing this in favor of what's already on main. |
What are the relevant tickets?
Closes the analytics-types drift tracked alongside mitodl/ol-analytics-api#29 and #33. Related: mitodl/ol-analytics-api#37, which makes this file generated rather than hand-written.
Description (What does it do?)
frontends/api/src/analytics/types.tsmirrors ol-analytics-api's response models by hand. It has fallen behind them twice over.The
*_pkfields were typednumberand have never been numeric.contract_pk,courserun_pkandprogram_pkare dbt surrogate keys —dbt_utils.generate_surrogate_keyMD5-hashes its inputs into a 32-character hex string. ol-analytics-api#29 fixed the same mistake server-side, where it was not cosmetic:contract-utilization,enrollment-funnelandprogram-funnelwere 500ing in production on a Pydanticint_parsingerror (SentryOL-ANALYTICS-API-J, 120 events in the first two minutes).Nothing breaks on this side: every use is a React key, a
Mapkey orSetmembership, and all three behave identically for strings. But theMap<number, EnrollmentCompletionFunnel[]>inCoursePerformanceTablewas only well-typed because the type it read was wrong, so it moves toMap<string, …>here.The activity totals went nullable and seven columns were missing. ol-analytics-api#33 floors each activity total through the cohort that produced it rather than through its own magnitude, so
total_videos_watched/total_problems_attempted/total_chatbot_interactionscome backnullwhen few enough learners are behind them — a large total suppresses. All three were still typed non-null. The five cohort counts that change added toMonthlyEngagementTrend(enrolling_learners,certified_learners,video_watchers,problem_attempters,chatbot_users) were missing entirely, as werevideo_watchersandproblem_attemptersonContentEngagementDepth.Nothing renders wrong today.
EngagementTrendChartplots onlynew_enrollmentsandcertificates_earned, both already nullable and already handled — it shows a suppressed indicator and mapsrow[series.key] ?? null. The three activity totals are deliberately not charted at all — the component's comment explains they sit on a different y-scale, and a dual-axis chart would invite comparing two things that were never on the same scale.The live hazard was
test-utils/factories.ts, which built fixtures withfaker.number.int()pks. Every test asserting on one was agreeing with a shape production does not send. It now generates 32-character lowercase hex, and carries the seven added columns.Scope
Fields were checked against
models.pyonol-analytics-api@main, not against the ticket, and stop there deliberately:contract_idand the contract-grained models arrive with ol-analytics-api#34, which has not merged. This PR syncs to what is deployed.This file is on its way out
Third time these types have been chased by hand (see also the
sso_organization_idshim). ol-analytics-api#37 now publishes an OpenAPI document per tenant and commits it, and the generatedtypescript-axiosclient was verified to produce correct nullability and distinct per-model interfaces, typechecking clean undertsc --strict. Once the clients repo and the ConcoursePIPELINE_CONFIGSentry land,types.ts,clients.tsand the./analytics-typesexport all go away.How can this be tested?
main's typecheck carries 80 pre-existing errors in this environment (PagePropsfrom Next's generated types, and@/public/*image module declarations) — the count is identical with and without this change, and none of them are in analytics files.All four Analytics suites plus
AnalyticsContent.test.tsxpass (50 tests).CoursewareDisplay/HomeEnrollmentsDisplayandUnenrolledCourseCard.complianceflaked on 5s timeouts in one full parallel run; both pass standalone with these changes applied, and neither file references analytics at all.Screenshots (if appropriate)
None — types and fixtures only, no rendered output changes.
🤖 Generated with Claude Code
https://claude.ai/code/session_01AVSXwars1LvgtqV1YWhrB1