Stop Content Optimizer spinning forever on a failed competitor analysis - #28
Merged
Merged
Conversation
Two halves of one defect, both because a FAILED per-URL request is indistinguishable from a pending one when you only look at `data`. The table cells rendered loading dots whenever `competitorsAuthorized && analysis === undefined`. A rejected query also has `data === undefined`, so those cells spun FOREVER — the page never settled, and nothing said why. The headline cards were worse. `analysesPending` is `analysisQueries.some(q => q.isLoading)`, which goes false when requests SETTLE, successfully or not. So once every analysis had failed, the target cards read "No data" — which claims the top-ranking pages have nothing to measure, when the truth is we could not measure them. On a paid feature, that is a wrong answer presented as a finding. Failures are now tracked separately: cells say "failed" with a tooltip instead of spinning, and the cards say "Could not analyze the top pages" instead of "No data". Worth noting the surrounding code was already careful about the money here — `retry: 0` with a comment explaining that react-query's retry would double the billed invocations. The gap was reporting the failure, not causing it. ci:check clean, 2,122 tests passing. Not browser-verified: reproducing it needs a paid brief where a competitor page analysis rejects. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Deploying with
|
| Status | Name | Latest Commit | Updated (UTC) |
|---|---|---|---|
| ✅ Deployment successful! View logs |
flyrocketseo | a33591b | Jul 31 2026, 06:23 AM |
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.
Closes the last defect from the Lane 4 audit.
Two halves of one bug
Both because a failed per-URL request is indistinguishable from a pending
one when you only look at
data.The cells spun forever. They rendered loading dots whenever
competitorsAuthorized && analysis === undefined. A rejected query also hasdata === undefined, so those cells never stopped — the page never settled, andnothing said why.
The headline cards were worse.
analysesPendingisanalysisQueries.some(q => q.isLoading), which goes false when requestssettle — successfully or not. So once every analysis had failed, the target
cards read:
That claims the top-ranking pages have nothing to measure. The truth was that we
couldn't measure them. On a paid feature, that's a wrong answer presented as a
finding — someone could size an article against it.
Now
Failures are tracked in their own
Set/count rather than inferred from missingdata, so the three states — pending, failed, absent — stay distinct.
Worth noting
The surrounding code was already careful about the money:
retry: 0with acomment explaining that react-query's retry would double the billed invocations.
The gap was reporting the failure, not causing it.
Verification
pnpm ci:checkclean, 2,122 tests passing.Not browser-verified: reproducing it needs a paid brief where a competitor
page analysis rejects.
🤖 Generated with Claude Code