Skip to content

fix(update): retry post-install smoke check and surface verification failure#241

Merged
elkaix merged 3 commits into
mainfrom
fix/update-smoke-check-retry
Jul 23, 2026
Merged

fix(update): retry post-install smoke check and surface verification failure#241
elkaix merged 3 commits into
mainfrom
fix/update-smoke-check-retry

Conversation

@elkaix

@elkaix elkaix commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Retry the post-install smoke check (3 attempts, 1s apart) before recording VERIFICATION_FAILED. Homebrew can report success moments before its opt launcher symlink is repointed at the new keg; the single immediate probe then exercised the OLD binary, reported the old version, and recorded a false VERIFICATION_FAILED — leaving the footer stuck on the stale "↑ Update available" notice after a successful upgrade (observed live on a 0.60.0 → 0.62.0 brew upgrade). A genuinely bad install still fails every attempt.
  • Run the probe off the event loop (asyncio.to_thread) so the up-to-10s --version subprocess can no longer stall the shell.
  • Surface verification failure on screen: when the smoke check ultimately fails with print_output=True, print the Updated, but smoke check did not pass: … message where "Updated successfully!" was shown, so the visible outcome matches the recorded status (failure-truthfulness / C01/C13).
  • Deflake three spinner tests: they guard against the old static "Working…" placeholder by asserting "Working" not in rendered, but the spinner verb rotates on wall-clock through a list that legitimately includes "Working" — the suite failed deterministically for that verb's 10-minute rotation window every ~21 hours (it blocked this branch's first push). The tests now pin spinner_message.

Testing

  • New test_update_job_smoke_check_retry_absorbs_launcher_relink_race (fail-then-pass → UPDATED, retry logged) and the existing verification-failure test now asserts all attempts run.
  • make check-pythinker-code green (ruff + pyright + ty); full make test-pythinker-code green via the pre-push gate.

Changelog

## Unreleased entry added.

Summary by CodeRabbit

  • Bug Fixes

    • Improved post-update verification by retrying transient smoke-check failures.
    • Prevented failed verifications from displaying a misleading “Updated successfully!” message.
    • Verification failures are now clearly shown on screen.
  • Tests

    • Stabilized spinner-related tests to avoid time-dependent failures.
    • Added coverage for verification retries and launcher relink race conditions.

elkaix added 2 commits July 22, 2026 20:44
…failure

The smoke check ran once, immediately after the package-manager upgrade.
Homebrew can report success moments before its opt launcher symlink is
repointed at the new keg, so the probe exercised the old binary, reported
the old version, and recorded a false VERIFICATION_FAILED — leaving the
footer stuck on the stale update notice while the screen said "Updated
successfully!".

Retry the smoke check up to 3 times, 1s apart, off the event loop
(asyncio.to_thread) so the probe can no longer block the shell either.
When verification genuinely fails after all attempts, print the failure
where the install success was shown so the on-screen outcome matches the
recorded status.
…guards

Three tests assert 'Working' is absent from the rendered activity spinner
to guard against the old static 'Working…' placeholder. The verb rotates
on time.monotonic() over a list that legitimately includes 'Working', so
the suite fails deterministically for the verb's 10-minute rotation
window every ~21 hours. Pin spinner_message in those tests so the guard
only catches the real regression.
@coderabbitai

coderabbitai Bot commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

You’ve reached a temporary PR review limit under our Fair Usage Limits Policy.

Your recent review volume is higher than typical usage, so adaptive limits are currently applied.

Next review available in: 37 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: a52ddd32-0e14-4dc6-b400-4094dc7dcbe3

📥 Commits

Reviewing files that changed from the base of the PR and between 92e95af and 4d72f2e.

📒 Files selected for processing (2)
  • src/pythinker_code/ui/shell/update_orchestrator.py
  • tests/ui_and_conv/test_update_orchestrator.py
📝 Walkthrough

Walkthrough

The update orchestrator now retries post-install smoke checks asynchronously, reports final verification failures on screen, and tests transient and persistent failures. UI spinner tests pin rotating text to deterministic output.

Changes

Update verification

Layer / File(s) Summary
Async smoke-check retry and failure reporting
src/pythinker_code/ui/shell/update_orchestrator.py, CHANGELOG.md
Post-install verification runs through an asynchronous retry helper, logs retry attempts, and prints final failures instead of leaving a success message visible.
Verification retry coverage
tests/ui_and_conv/test_update_orchestrator.py
Tests cover exhausted retries and recovery from a transient launcher relink failure, including persisted update success state and retry logging.
Deterministic spinner assertions
tests/ui_and_conv/test_empty_think_part_indicator.py, tests/ui_and_conv/test_modal_lifecycle.py
Spinner text is fixed during UI assertions to avoid time-based message rotation.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant UpdateJob
  participant RetryHelper
  participant SmokeCheck
  participant Console
  UpdateJob->>RetryHelper: await post-install verification
  RetryHelper->>SmokeCheck: run smoke check in worker thread
  SmokeCheck-->>RetryHelper: verification result
  RetryHelper->>RetryHelper: retry transient failure
  RetryHelper-->>UpdateJob: final result
  UpdateJob->>Console: print verification failure
Loading

Possibly related PRs

Suggested labels: bug

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description includes summary, testing, and changelog notes, but omits the template's Related Issue and Checklist sections. Add the Related Issue section with Resolve #(issue_number) and include the full Checklist items from the template.
Docstring Coverage ⚠️ Warning Docstring coverage is 40.00% which is insufficient. The required threshold is 70.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title follows the required conventional commits format and accurately summarizes the main change.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/update-smoke-check-retry

Warning

Billing warning: we have not been able to collect payment for this subscription for more than 72 hours. Please update the payment method or pay any pending invoices in Billing to avoid service interruption.


Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/pythinker_code/ui/shell/update_orchestrator.py`:
- Around line 575-584: Update _run_smoke_check_with_retry and its cancellation
handling so asyncio cancellation during run_post_install_smoke_check produces a
terminal job status before run_update_job releases the update lock. Ensure the
smoke-check thread/subprocess is not left running untracked, while preserving
the existing retry behavior for non-cancellation failures.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 50d84c1f-2c76-4861-a9d1-063e5d11f8c9

📥 Commits

Reviewing files that changed from the base of the PR and between 30d2cf3 and 92e95af.

📒 Files selected for processing (5)
  • CHANGELOG.md
  • src/pythinker_code/ui/shell/update_orchestrator.py
  • tests/ui_and_conv/test_empty_think_part_indicator.py
  • tests/ui_and_conv/test_modal_lifecycle.py
  • tests/ui_and_conv/test_update_orchestrator.py

Comment thread src/pythinker_code/ui/shell/update_orchestrator.py
@codecov

codecov Bot commented Jul 23, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 84.21053% with 3 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
src/pythinker_code/ui/shell/update_orchestrator.py 84.21% 1 Missing and 2 partials ⚠️

📢 Thoughts on this report? Let us know!

Cancellation lands on the job's await points and skipped the failure
handler, releasing the update lock while the status file still said
RUNNING. Catch CancelledError, write a terminal FAILED status, and
re-raise.
Comment thread tests/ui_and_conv/test_update_orchestrator.py
@elkaix
elkaix merged commit 9700655 into main Jul 23, 2026
37 checks passed
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