fix(course-optimizer): fix start-analysis run-id assumption, polling, and not-started copy - #114
Open
nsprenkle wants to merge 5 commits into
Open
fix(course-optimizer): fix start-analysis run-id assumption, polling, and not-started copy#114nsprenkle wants to merge 5 commits into
nsprenkle wants to merge 5 commits into
Conversation
There was a problem hiding this comment.
🟡 Changes recommended
Polling can stop after an initial 404 before the asynchronously created run becomes available.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
Updates the Course Optimizer frontend for Studio’s asynchronous 202 Accepted analysis-start response.
Changes:
- Removes the unused run ID from the POST API.
- Updates polling, invalidation, and related tests.
- Revises pre-analysis messaging and headings.
File summaries
| File | Summary |
|---|---|
src/optimizer-page/extended/messages.ts |
Updates no-run messaging. |
src/optimizer-page/extended/data/apiHooks.ts |
Adjusts asynchronous startup polling and invalidation. |
src/optimizer-page/extended/data/apiHooks.test.tsx |
Updates polling and mutation tests. |
src/optimizer-page/extended/data/api.ts |
Makes the start API return void. |
src/optimizer-page/extended/data/api.test.ts |
Updates POST API tests. |
src/optimizer-page/extended/CourseOptimizerReportBody.tsx |
Adds the no-run heading. |
src/optimizer-page/extended/CourseOptimizerReportBody.test.tsx |
Verifies updated no-run content. |
src/optimizer-page/CourseOptimizerExtendedPage.test.tsx |
Updates queued-start test fixtures. |
Review details
- Files reviewed: 8/8 changed files
- Comments generated: 1
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
…alysis POST The edx-platform companion PR moves the course export + upload to xpert-ai-workflows into a background Celery task, since it could take long enough on large courses to risk a proxy/gateway timeout. Studio's POST endpoint now returns 202 immediately (before a run exists) instead of proxying the backend's real response, so it can no longer hand back a run id synchronously. Nothing in the UI actually consumed the returned runId -- the page only relies on isPending/isError plus the existing status poll, which already treats "no run yet" as still-pending -- so this is a type/response-shape cleanup with no behavior change for users. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
useCourseOptimizerReport treated a 404 (course has no run yet) as "pending" and kept polling every 2s indefinitely, hammering Studio with repeated 404s for a course whose analysis was never started. Poll only while a real run is actively in progress -- starting one still updates immediately via useStartCourseAnalysisReport's own invalidateQueries call, so nothing relied on the removed fallback polling. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
notStartedHeading was defined but never rendered, leaving the "no run yet" state as a single muted line with no explicit heading -- easy to mistake for an error state at a glance despite already being handled as a distinct case (isError vs. a null run). Render the heading, and reword both messages to name the state and point at the scan button directly. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
nsprenkle
force-pushed
the
nsprenkle/course-optimizer-async-analysis
branch
from
September 11, 2026 15:14
4c20d56 to
64213e9
Compare
…t race The start-analysis POST only queues a background export/upload task (edx-platform#466) -- the run isn't visible to the status endpoint the instant it resolves. Combined with the prior commit's fix to stop polling on a null result, a still-null refetch right after starting a run could get stuck in the not-started state forever, since nothing would trigger another check. useCourseOptimizerReport now takes an `awaitingRun` flag (true from a successful start until a run appears) so it keeps polling through that gap without reintroducing indefinite polling for a course that was never scanned. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
edx-platform#466 (ea9a0d03c6) now marks a just-started run PENDING in its own cache synchronously before the start POST returns, so the status endpoint never actually returns null right after a start succeeds -- the race this commit's awaitingRun flag was bridging can no longer happen. Reverts to the simpler, already-correct polling logic rather than keeping defensive client-side coordination for a gap that's now closed at the source. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Follow-up to #109. Three small fixes to the Course Optimizer extended report's start/poll cycle, found while testing #109 end-to-end against a devstack:
1. Stop expecting a run id from the start-analysis POST
In combination with edx/edx-platform#466 (which moved course export / compress to an async task), Studio's POST endpoint now returns
202 {"status": "pending"}immediately, before a run exists, rather than proxying the backend's real{run_id, ...}response synchronously.This updates
postCourseAnalysisReportto returnvoidinstead of{ runId }, since nothing here actually consumed that value --CourseOptimizerExtendedPageonly ever usedisPending/isErrorfrom the mutation.2. Stop polling analysis status when no run exists
useCourseOptimizerReport'srefetchIntervalused to treat anullresult (course has no run yet -- Studio proxies a 404 in that case) the same as an actively-pending run, and polled every 2s indefinitely -- hammering Studio with repeated 404s for a course whose analysis was never started. It now only polls while a run actually exists and is in an active status (PENDING/RUNNING/PARTIAL).This is a real behavior change from what #109 originally shipped (and from what this PR's own first commit above assumed): starting a run in the same browser tab still works immediately, since
useStartCourseAnalysisReport'sonSuccessexplicitly invalidates the query rather than relying on the interval. The one tradeoff: a run started in a different tab/session for the same course won't be picked up here until the page is reloaded, since polling no longer runs speculatively while there's no run to check on.3. Clarify the never-scanned state vs. a load error
The "no run yet" state was a single muted line of body text with no heading (
notStartedHeadingwas defined inmessages.tsbut never actually rendered), easy to mistake for an error state at a glance. Now renders a clear heading ("No previous scans found for this course") and points directly at the scan button, kept visually distinct from the real load-error state (isError).Supporting information
Companion PR: edx/edx-platform#466
Testing instructions
npm test -- src/optimizer-pageshould pass.npm run typesshould pass.