Stop failed and never-run queries claiming to be answers - #35
Open
ThinkingSpade wants to merge 1 commit into
Open
Stop failed and never-run queries claiming to be answers#35ThinkingSpade wants to merge 1 commit into
ThinkingSpade wants to merge 1 commit into
Conversation
Four places where a query that FAILED, or never ran at all, was rendered as a
confident statement about the world. Found by a Codex audit of the two surfaces
reported as "fields not filled out, no error"; each is verified against the
source rather than taken on trust.
The rule applied throughout is the one `resolveQueryState` already encodes:
failure outranks emptiness, because a failed query has no rows *because it
failed*. These call sites simply predated it.
1. LINK GAP -- the worst of them (CompetitorsTabBody.tsx)
`rows={linkGapQuery.data?.rows ?? []}` fed a table whose zero-row message is:
"No link gap found -- every domain linking to this competitor also links
to you."
That is a strong, flattering claim about the user's backlink profile, and a
comparison they never paid for could make it. Same shape for Keyword Gap's
"No keywords found for this comparison".
2. COMPETITOR DISCOVERY (CompetitorsTabBody.tsx / CompetitorsPage.tsx)
`competitorsQuery.data?.rows ?? restored?.result.rows ?? []` collapsed
failure, never-run and genuine-zero into one empty array, which the table
reported as:
"No competitors found. Try a domain with more organic visibility."
-- a claim about the user's site when in fact we never got an answer. Codex
identified the trigger: hard-refreshing a URL containing `target`.
Authorization is mount-session state so it resets to false, while
auto-restore is only enabled when `target` is EMPTY, so neither the live
query nor the stored run fires.
The caller now passes what those rows MEAN (`isError` / `isFetching` /
`hasResult`), because the array alone cannot say. A restored past run counts
as a real answer.
3. KEYWORD GAP TOTALS (KeywordGapOverview.tsx)
Only the active mode is fetched -- correct, the other two are separately
metered and must not auto-run. But a disabled react-query stays `isPending`
forever, so the other two cards sat on loading dots indefinitely, reading as
"still working" rather than "not run". Dots now mean `isFetching`; otherwise
the card says "Select to run".
4. PAGE EXPLORER BACKLINKS (PageExplorerService.ts, page-explorer.ts,
PageExplorerResults.tsx)
The backlink lookup is a separate best-effort subcall: on failure it is
caught, logged, `backlinks` stays null, and the parent result still
succeeds. Right call -- a Backlinks API hiccup should not sink the keyword
view -- but a FAILED PAID SUBCALL and a page that genuinely has no backlink
data both rendered as two dashes with nothing to tell them apart. This is
the most likely thing behind the original "Backlinks and Ref. domains show
dashes" report.
Adds `backlinksStatus: "available" | "no-data" | "error"`. The
`.default("no-data")` is load-bearing: a required field would fail
`safeParse` against every already-cached payload, and auto-restore drops a
failed parse SILENTLY, so old runs would quietly stop restoring.
DELIBERATELY NOT "FIXED"
Several blanks are correct under the no-auto-spend rule and only needed honest
wording, never a fetch: Keyword Gap's inactive modes, Link Gap not auto-running
from URL state, and the restored Page Explorer snapshot. Nothing here starts a
metered request that did not start before -- every change is presentational or
adds a status field.
STILL OUTSTANDING from the same audit
- `useAutoRestoredRun` callers ignore its `isError`, and a schema-mismatch
parse failure returns null with no error state at all, so a run you performed
can vanish silently.
- `PageExplorerPage.tsx:129` -- `snapshotQuery.data ?? null`, `isError` never
read, so a failed on-page fetch removes the whole card.
- `RecentRunsList.tsx:31` -- `query.data ?? []`, and selection failures are
swallowed by `.catch(() => undefined)`.
VERIFICATION
pnpm ci:check clean; 2,129 tests passing across 224 files; tsc clean. Not yet
exercised in a browser against live failing queries -- the states are reachable
by construction but the wording has not been seen on screen.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Deploying with
|
| Status | Name | Latest Commit | Updated (UTC) |
|---|---|---|---|
| ✅ Deployment successful! View logs |
flyrocketseo | 31547b7 | Aug 01 2026, 06:30 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.
Stop failed and never-run queries claiming to be answers
Four places where a query that FAILED, or never ran at all, was rendered as a
confident statement about the world. Found by a Codex audit of the two surfaces
reported as "fields not filled out, no error"; each is verified against the
source rather than taken on trust.
The rule applied throughout is the one
resolveQueryStatealready encodes:failure outranks emptiness, because a failed query has no rows because it
failed. These call sites simply predated it.
LINK GAP -- the worst of them (CompetitorsTabBody.tsx)
rows={linkGapQuery.data?.rows ?? []}fed a table whose zero-row message is:"No link gap found -- every domain linking to this competitor also links
to you."
That is a strong, flattering claim about the user's backlink profile, and a
comparison they never paid for could make it. Same shape for Keyword Gap's
"No keywords found for this comparison".
COMPETITOR DISCOVERY (CompetitorsTabBody.tsx / CompetitorsPage.tsx)
competitorsQuery.data?.rows ?? restored?.result.rows ?? []collapsedfailure, never-run and genuine-zero into one empty array, which the table
reported as:
"No competitors found. Try a domain with more organic visibility."
-- a claim about the user's site when in fact we never got an answer. Codex
identified the trigger: hard-refreshing a URL containing
target.Authorization is mount-session state so it resets to false, while
auto-restore is only enabled when
targetis EMPTY, so neither the livequery nor the stored run fires.
The caller now passes what those rows MEAN (
isError/isFetching/hasResult), because the array alone cannot say. A restored past run countsas a real answer.
KEYWORD GAP TOTALS (KeywordGapOverview.tsx)
Only the active mode is fetched -- correct, the other two are separately
metered and must not auto-run. But a disabled react-query stays
isPendingforever, so the other two cards sat on loading dots indefinitely, reading as
"still working" rather than "not run". Dots now mean
isFetching; otherwisethe card says "Select to run".
PAGE EXPLORER BACKLINKS (PageExplorerService.ts, page-explorer.ts,
PageExplorerResults.tsx)
The backlink lookup is a separate best-effort subcall: on failure it is
caught, logged,
backlinksstays null, and the parent result stillsucceeds. Right call -- a Backlinks API hiccup should not sink the keyword
view -- but a FAILED PAID SUBCALL and a page that genuinely has no backlink
data both rendered as two dashes with nothing to tell them apart. This is
the most likely thing behind the original "Backlinks and Ref. domains show
dashes" report.
Adds
backlinksStatus: "available" | "no-data" | "error". The.default("no-data")is load-bearing: a required field would failsafeParseagainst every already-cached payload, and auto-restore drops afailed parse SILENTLY, so old runs would quietly stop restoring.
DELIBERATELY NOT "FIXED"
Several blanks are correct under the no-auto-spend rule and only needed honest
wording, never a fetch: Keyword Gap's inactive modes, Link Gap not auto-running
from URL state, and the restored Page Explorer snapshot. Nothing here starts a
metered request that did not start before -- every change is presentational or
adds a status field.
STILL OUTSTANDING from the same audit
useAutoRestoredRuncallers ignore itsisError, and a schema-mismatchparse failure returns null with no error state at all, so a run you performed
can vanish silently.
PageExplorerPage.tsx:129--snapshotQuery.data ?? null,isErrorneverread, so a failed on-page fetch removes the whole card.
RecentRunsList.tsx:31--query.data ?? [], and selection failures areswallowed by
.catch(() => undefined).VERIFICATION
pnpm ci:check clean; 2,129 tests passing across 224 files; tsc clean. Not yet
exercised in a browser against live failing queries -- the states are reachable
by construction but the wording has not been seen on screen.
Co-Authored-By: Claude Opus 5 noreply@anthropic.com