Skip to content

fix(ui): retry the prerequisite probe after a transient failure#20

Merged
ashproto merged 5 commits into
nextfrom
fix/prereq-retry-after-failed-probe
Jul 17, 2026
Merged

fix(ui): retry the prerequisite probe after a transient failure#20
ashproto merged 5 commits into
nextfrom
fix/prereq-retry-after-failed-probe

Conversation

@ashproto

Copy link
Copy Markdown
Owner

Addresses the P2 Codex flagged on #19 (the next → main promotion): a transient prerequisite-probe failure permanently disabled the safety gate.

Root cause: in the shared prerequisites singleton, probe()'s catch reset check to null but left loading holding the resolved promise. load() is guarded by if (!loading), so it became a no-op for the rest of the session — canEditHistory stayed true (history editing wrongly enabled), the warning banner stayed hidden, and nothing re-probed (refresh() is only called from the focus handler, which itself guarded on check).

Fix:

  • prerequisites.svelte.ts — reset loading = null in the catch, so a later load() / refresh() actually re-probes.
  • PrereqBanner.svelte — broadened the focus-refresh guard from check && !canEditHistory to !check || !canEditHistory, so a failed probe (check === null) also retries on window focus.

Once this merges to next, #19 will include the fix.

Testing: npm run check 0 errors · npm test 296 passed.

🤖 Generated with Claude Code

Code review (PR #19) caught that a transient prerequisite-probe failure wedged
the shared singleton: probe()'s catch reset `check` to null but left `loading`
holding the resolved promise, so load() no-op'd for the rest of the session —
canEditHistory stayed true (history editing wrongly enabled) and the banner
stayed hidden, with no retry path.

- prerequisites.svelte.ts: reset `loading = null` in the catch so a later
  load()/refresh() actually re-probes.
- PrereqBanner.svelte: re-probe on window focus when the probe hasn't succeeded
  (check === null), not only when a prerequisite is known-missing.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@chatgpt-codex-connector

Copy link
Copy Markdown

💡 Codex Review

get canEditHistory() {
return check ? check.git && check.python3 && check.filterRepo : true;
},

P2 Badge Keep history editing disabled after a failed probe

When the startup probe rejects, probe() resets check to null, and this getter consequently reports that history editing is available. Both initial callers share that failed request, and the only subsequent retry is the banner's window-focus listener, so a user who remains in the app sees no warning and can invoke the destructive rewrite despite prerequisites being unverified. Track probe failure separately or keep editing disabled until a successful check confirms availability.


return (
kind !== "NotFound" &&
kind !== "NotAuthed" &&
kind !== "NoRemote" &&
kind !== "NotInstalled"

P2 Badge Stop retrying explicit rate-limit failures

A backend RateLimited error passes this predicate, so fetchActivityWithRetry repeats the same GitHub API call five times and delays the visible error by six seconds. An explicit rate limit will not normally clear within this fixed backoff, and the extra requests can prolong throttling; reserve these short retries for the cold-cache computing/parse case, or wait until the reported reset time.

ℹ️ 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".

ashproto and others added 2 commits July 17, 2026 10:18
Codex (PR #20 review) noted the first fix still left the destructive rewrite
reachable: canEditHistory returned true whenever `check` was null, which
includes a FAILED probe — so between a transient failure and a successful
retry, "Rewrite history" ran on unverified prerequisites with no warning.

Track the failure separately: a new `probeFailed` flag distinguishes "probe
rejected" from "not probed yet". canEditHistory now allows only when a probe
succeeded or hasn't run yet (optimistic pre-first-probe / non-Tauri), and stays
DISABLED once a probe has failed until a later probe succeeds. Guard the probe
with isTauri so the browser preview stays "unknown", not "failed".

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Codex (PR #20 review) flagged that isRetryableActivityError retried a
RateLimited error, so fetchActivityWithRetry hit the same endpoint five times
over ~6s — a rate limit won't clear inside that fixed backoff, and re-hitting
it prolongs the throttle.

Narrow the predicate to the transient cold-cache case only: retry `Other`/parse
errors and non-GithubError blips; do NOT retry RateLimited, Forbidden, or the
permanent kinds. Update the unit tests accordingly.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@ashproto

Copy link
Copy Markdown
Owner Author

Both P2s addressed:

  • canEditHistory after a failed probe (09d26f9): added a probeFailed flag so editing stays disabled after a rejected probe — the getter was returning true for any null check, which included a failed probe, leaving the destructive rewrite reachable on unverified prerequisites. "Not probed yet" / non-Tauri stays optimistic (no flash of disabled); a later successful probe re-enables it.
  • rate-limit retries (d39fb48): narrowed isRetryableActivityError to the transient cold-cache case only (Other/parse errors + non-GithubError blips). RateLimited, Forbidden, and the permanent kinds no longer retry — so an explicit rate limit surfaces immediately instead of being re-hit five times over ~6s.

Gate: npm run check 0 errors · npm test 296 pass (activity retry-policy tests updated).

@chatgpt-codex-connector

Copy link
Copy Markdown

💡 Codex Review

refresh() {
loading = probe();
return loading;

P2 Badge Serialize overlapping prerequisite refreshes

When a focus event calls refresh() while the initial probe or a prior refresh is still running, this unconditionally starts another probe, and both probes can update check and probeFailed. If the newer probe succeeds after prerequisites are installed but the older probe completes later with a failure or stale missing-tools result, the older response disables history editing again until another focus cycle. Reuse the in-flight promise or ignore results from superseded probes.

ℹ️ 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".

…e editing

Codex (PR #20 re-review) flagged a race: refresh() (window-focus) can start a
probe while another is still in flight, and both write check/probeFailed on
completion. A newer success followed by an older failure completing late would
clobber the good result and wrongly re-disable history editing until the next
focus cycle.

Add a monotonic probeSeq: each probe captures its id and commits its result
only if it is still the latest, so superseded/out-of-order completions are
dropped.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@ashproto

Copy link
Copy Markdown
Owner Author

Fixed in dc01bb6. Added a monotonic probeSeq: each probe captures its id and commits check/probeFailed only if it is still the latest, so a superseded / out-of-order completion (an older failure landing after a newer success) is dropped instead of re-disabling editing.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: dc01bb6b1e

ℹ️ 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".

Comment thread src/lib/prerequisites.svelte.ts Outdated
Codex (PR #20 re-review) flagged that a still-pending initial probe left
canEditHistory true (check null), so a slow probe let "Rewrite history" run
before git/python3/filter-repo were verified — the probeFailed flag only
covered the FAILED case, not the pending one.

Make canEditHistory optimistic only in non-Tauri (browser preview): in the
desktop app any non-success check (pending, failed, or unprobed) keeps editing
DISABLED until a successful probe confirms availability. This subsumes the
probeFailed flag, which is removed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@ashproto
ashproto merged commit dfb19bf into next Jul 17, 2026
2 checks passed
@ashproto
ashproto deleted the fix/prereq-retry-after-failed-probe branch July 17, 2026 18:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant