Skip to content

test(ci): say what the self-update test can and cannot observe - #102

Merged
krassx merged 2 commits into
mainfrom
test/self-update-helper-honest
Nov 4, 2026
Merged

krassx merged 2 commits into
mainfrom
test/self-update-helper-honest

Conversation

@krassx

@krassx krassx commented Nov 4, 2026 •

Copy link
Copy Markdown
Contributor

What

Follow-up to #100, which was merged while a review finding was still open. Comments and failure messages only; no behaviour change.

assert_cmd's .assert() returns only once every holder of the child's stdout/stderr has closed them, and the self-replace helper (and its cmd.exe) inherit those pipes. So the helper's single DeleteFileW attempt, which self-replace 1.5.0 and 1.5.1 never retry, is already over when the test looks at the directory. Consequences:

  • the earlier "the helper makes its single attempt after we poll" comment and the CI comment on --test-threads=1 were wrong;
  • a file still present means that attempt failed, not that the helper is slow, so the failure message now says so;
  • the wait stays generous (20 s): the helper's own .__selfdelete__.exe goes only when its last handle closes, which the pipes do not cover.

Not fixed here

The self-update (windows-11-arm) job failed once with both helper files left in %TEMP% (run 41677155537). That is probably something outside the test (e.g. a scanner) beating the helper's one delete; it is not confirmed. The product-side answer is in the follow-up PR that sweeps the leftovers on the next update.

🤖 Generated with Claude Code

https://claude.ai/code/session_01WeiJxQWhjhQvvURAjiDkti

assert() returns only once the self-replace helper (which inherits the
updater's pipes) has finished, so its single delete attempt is already over
when the leftovers are checked: a file still present means that attempt
failed, not that the helper is slow. Correct the comments and make the
failure message say so.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WeiJxQWhjhQvvURAjiDkti
@coderabbitai

coderabbitai Bot commented Nov 4, 2026 •

Copy link
Copy Markdown

Warning

Review limit reached

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Next included review available in 59 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available.

Learn how review limits work.

Review configuration:

Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: fba5d4f2-ea95-4f4c-b490-4461c62387ef
Commits

Reviewing files that changed from the base of the PR and between 5350c2a and d11dbcf.

Files selected for processing: 2
  • .github/workflows/ci.yml
  • tests/update_e2e.rs
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

Share

@claude

claude Bot commented Nov 4, 2026 •

Copy link
Copy Markdown

Claude finished @krassx's task in 38s —— View job


Review of PR #102

  • Read the diff and the surrounding test (tests/update_e2e.rs)
  • Checked the PR's claims against the self-replace 1.5.0 source
  • Posted findings

I didn't run the tests. The changed test is #[cfg(windows)] and this runner is Linux. I only read the code, and I downloaded the self-replace 1.5.0 source to check the helper's behaviour.

What I checked

  • The helper is spawned with Command::new(tmp_exe).spawn(), so it inherits the updater's stdout/stderr pipes.
  • The helper waits for the updater to exit, makes a single DeleteFileW call on the relocated binary, and exits with code 1 if that fails. It never retries.
  • It then spawns cmd.exe /c exit with bInheritHandles = TRUE. That process holds the DELETE_ON_CLOSE handle for the helper's own copy.
  • std's wait_with_output reads the pipes until every holder closes them.
  • So when .assert() returns, the DeleteFileW attempt is already over. The corrected comments and the new "a file still here means the attempt failed" wording are accurate.
  • The ci.yml comment is now correct. --test-threads=1 doesn't affect the helper's single attempt.
  • The only code change is the loop bound (80 → 8 iterations) and the failure message strings. Behaviour is otherwise unchanged.

Finding (inline, P3): the shorter 2 s wait is justified for the old binary. It is not clearly justified for the helper's own .__selfdelete__.exe in the temp dir. That file is removed by the DELETE_ON_CLOSE handle that cmd.exe closes at about the same moment the pipes close. A slow delete at that point would now fail the test with a message blaming the wrong file. I'd keep a longer wait for in_temp, or make the message cover both files. I wouldn't block on it.

Overall risk: Low. Only comments and failure messages changed, plus a shorter test-only wait. No product code is touched.

Merge recommendation: Approve. The P3 can be addressed here or in the follow-up PR about sweeping leftovers.

Most important issue: the wait for the temp-dir helper copy was cut from 20 s to 2 s (see above).

Positives

  • The corrected explanation is accurate and well reasoned.
  • The failure messages now say what a failure actually means.
  • The PR states plainly that the windows-11-arm failure is not explained by this change.

Comment thread tests/update_e2e.rs Outdated
// is slow. The short wait is only for the filesystem to settle.
let (mut left, mut in_temp) = (names_in(&bindir), names_in(&systemp));
for _ in 0..80 {
for _ in 0..8 {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Severity: P3 Low
Location: tests/update_e2e.rs:520 (and the messages at 530/534)
Problem: Cutting the wait from 20 s to 2 s is only justified for the old binary, which DeleteFileW removes before cmd.exe is spawned. The other file this loop waits for is the helper's own .__selfdelete__.exe in the temp dir. That file is removed by FILE_FLAG_DELETE_ON_CLOSE when the last inherited handle closes, and that handle is held by the cmd.exe /c exit that self-replace spawns (windows.rs, self_delete_on_init). The pipes close at the same moment, so .assert() returning does not prove that deletion has completed.
Impact: Any delay in that kernel-side delete, such as a scanner holding the file, now has 2 s of slack instead of 20 s. This could make the windows-11-arm job flakier, and the new message would blame the helper's single DeleteFileW attempt for something that attempt did not do.
Scenario: The old binary is gone and only .__selfdelete__.exe is left in systemp-N at 2 s. The test fails with "the helper exited without deleting the old binary", which is the wrong diagnosis.
Fix: Either keep a longer wait for in_temp only, or word the temp-dir message to cover both files (the relocated old binary and the helper copy). I would not make this blocking.

@cursor cursor 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.

Stale comment

Review of PR #102

Follow-up to #100: correct the comments and failure text for the Windows self-replace e2e, and cut the leftover poll from 20s to 2s. I reviewed the diff against tests/update_e2e.rs, src/cli/update.rs, .github/workflows/ci.yml, and self-replace 1.5.0 and 1.5.1 src/windows.rs (schedule_self_deletion_on_shutdown, self_delete_on_init, DeleteFileW once, ExitProcess(1) with no cmd.exe on failure, FILE_FLAG_DELETE_ON_CLOSE + CreateProcessA("cmd.exe /c exit") with bInheritHandles=TRUE). I did not run the Windows-only test (this host is Linux). I did read gh pr checks for this HEAD: self-update (windows-latest), self-update (windows-11-arm), test (windows-*), and clippy are green.

What the PR gets right

The load-bearing claim about .assert() is correct for the helper process:

  1. assert_cmd uses Command::output() → piped stdout/stderr and wait_with_output (read to EOF).
  2. self-replace starts the helper with Command::new(tmp_exe).spawn() (stdio inherit), so the helper holds those write ends.
  3. The helper’s .CRT$XCV path WaitForSingleObject(parent) then one DeleteFileW. It never retries in 1.5.0 or 1.5.1.
  4. EOF therefore cannot happen until the helper has already made that attempt (and, on the success path, until cmd.exe has also dropped the inherited pipe handles).

So the old “helper makes its single attempt after we poll” / “--test-threads=1 is so we watch that attempt” comments were wrong. --test-threads=1 still serializes the crate (clearer --nocapture logs, less AV overlap with the sentinel test); it does not change the helper’s retry policy. Poll-before---version from #100 is unchanged. No product code in this PR.

Finding

P3 Low — tests/update_e2e.rs:514-520 (messages at 530 / 534–536). See inline. In short: leftovers are not only “DeleteFileW failed.” Delete-pending names (relocated PE and .__selfdelete__.exe) remain visible until handles other than the pipes close. The 80→8 loop is a behaviour change; the new messages over-claim permanence. Not blocking given green Windows jobs on this HEAD and #103 stacked to sweep / relax this assertion.

Note: the PR body says “comments and failure messages only; no behaviour change.” The loop bound is a behaviour change. Worth correcting in the description so reviewers do not skip the wait cut.

Verdict

  1. Overall risk: Low — test comments/messages + a shorter test-only wait; bugsee-cli update is unchanged.
  2. Merge recommendation: Approve. The P3 can land as-is or be folded into #103 (which already replaces the “failed delete can never happen” assertion).
  3. Most important to fix: Optional — do not treat a 2s read_dir leftover as proof the single DeleteFileW failed; keep a longer in_temp bound or name both leftover kinds.
  4. Positives: The stdio / single-attempt analysis matches the crate; the CI comment no longer implies --test-threads=1 changes helper behaviour; the PR is explicit that run 41677155537 is a product leftover, not a slow helper.
Open in Web View Automation 

Sent by Cursor Automation: Bugsee code review

Comment thread tests/update_e2e.rs Resolved
The helper's own .__selfdelete__.exe is removed when the last handle to it
closes, which assert() returning does not prove. Keep the 20s wait and
soften the failure message accordingly.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WeiJxQWhjhQvvURAjiDkti
@claude

claude Bot commented Nov 4, 2026 •

Copy link
Copy Markdown

Claude finished @krassx's task in 19s —— View job


Review of PR #102 (re-review after the latest push)

I didn't run the tests. The changed test is #[cfg(windows)] and this runner is Linux. I read the diff and the surrounding test code.

Earlier finding: fixed. Commit d11dbcf puts the wait back to 80 × 250 ms (20 s). It also rewrites the comment so it says what the wait covers: the helper's .__selfdelete__.exe is removed only when its last handle closes, and a scanner may hold that handle. That was the P3 raised in the previous review (the wait cut to 2 s, with a message blaming the wrong file). The PR now matches its description: only comments and messages change, and the loop bound is untouched.

New findings: none worth an inline comment.

What I checked in the new state

  • tests/update_e2e.rs:514-519: the comment correctly says that when .assert() returns, the helper's single DeleteFileW attempt is already over. A file still present after 20 s means that attempt failed, or the file is held by something outside the pipes.
  • tests/update_e2e.rs:531: the next-to-binary message now says what was observed, with no cause attached.
  • tests/update_e2e.rs:535-536: the temp-dir message ("the helper did not delete what it was meant to (a failed delete is never retried)") is reasonable. It still implies a failed delete as the cause, and a scanner holding a DELETE_ON_CLOSE handle for more than 20 s would also trigger it. That is unlikely, and this is a test-only diagnostic, so I'm not reporting it as a finding.
  • .github/workflows/ci.yml:148-149: the --test-threads=1 comment no longer claims it affects the helper's single attempt. It now gives the real reasons: failure attribution and less load on slow runners.
  • No product code, wire shapes, exit codes or --help text are touched, so the CLAUDE.md contracts are unaffected.

1. Overall risk: Low. Comments and failure messages only, with no behaviour change.

2. Merge recommendation: Approve. I can't submit a formal approval.

3. Most important issues to fix: none.

4. Positives

  • The explanation of why assert_cmd waiting on the pipes means the helper's attempt is already over is accurate.
  • The PR says plainly that the windows-11-arm leftover from run 41677155537 is not explained by this change, and that the product-side sweep belongs in the follow-up PR.
  • The author took the earlier review point and restored the generous wait instead of arguing for the cut.
    · branch test/self-update-helper-honest

@cursor cursor 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.

Review of PR #102 (re-review of d11dbcf)

Follow-up to #100: correct what the Windows self-replace e2e claims it can observe. I re-reviewed HEAD d11dbcf against tests/update_e2e.rs, src/cli/update.rs, .github/workflows/ci.yml, and self-replace 1.5.0 and 1.5.1 src/windows.rs (schedule_self_deletion_on_shutdown, self_delete_on_init, one DeleteFileW, ExitProcess(1) with no cmd.exe on failure, FILE_FLAG_DELETE_ON_CLOSE + CreateProcessA("cmd.exe /c exit") with bInheritHandles=TRUE). This host is Linux, so I did not run the Windows-only test. I did read CI for this HEAD: both self-update (windows-*) jobs succeeded; test (windows-11-arm), clippy, rustfmt, and e2e succeeded.

The prior P3 on 5f4a48d (80→8 wait + “nothing will remove it later”) is fully addressed. The loop is 80 × 250ms again, the comment now names the helper copy / DELETE_ON_CLOSE / a scanner handle, and the bindir message no longer assigns a cause. Versus main, this is comments and assertion strings only; the wait bound is unchanged.

What the PR gets right

The load-bearing claim about .assert() is still correct for the helper process:

  1. assert_cmd uses Command::output() → piped stdout/stderr, wait(), then read_to_end until EOF.
  2. self-replace starts the helper with Command::new(tmp_exe).spawn() (stdio inherit), so the helper holds those write ends.
  3. The helper’s .CRT$XCV path WaitForSingleObject(parent) then one DeleteFileW. It never retries in 1.5.0 or 1.5.1.
  4. On the success path, cmd.exe also inherits the pipes, so EOF cannot happen until that process has dropped them too.

So the old “helper makes its single attempt after we poll” / “--test-threads=1 is so we watch that attempt” comments were wrong. --test-threads=1 still serializes the crate (clearer --nocapture logs, less overlap with the other update tests); it does not change the helper’s retry policy. Poll-before---version from #100 is unchanged. No product code, wire shapes, exit codes, or --help text in this PR.

Findings

None (no P0–P3).

Not re-raised: the temp-dir panic still parenthesizes “a failed delete is never retried.” That is the right diagnosis for a hard DeleteFileW miss of .__relocated__.exe. It is slightly wrong if the leftover after 20s is a scanner-held .__selfdelete__.exe. The comment above the loop already covers that case, the wait matches main, and the ARM leftover from run 41677155537 is a product issue for #103. Test-only diagnostic; not a failure scenario this change introduces.

Verdict

  1. Overall risk: Low — comments and failure messages; bugsee-cli update is unchanged.
  2. Merge recommendation: Approve.
  3. Most important to fix: Nothing in this PR.
  4. Positives: The stdio / single-attempt analysis matches the crate; the restored wait matches what the pipes do not cover; the CI comment no longer implies --test-threads=1 changes helper behaviour; the PR is explicit that run 41677155537 is a product leftover, not a slow helper.
Open in Web View Automation 

Sent by Cursor Automation: Bugsee code review

@krassx
krassx merged commit c651d4e into main Nov 4, 2026
@krassx
krassx deleted the test/self-update-helper-honest branch November 4, 2026 13:04
@krassx krassx mentioned this pull request Nov 4, 2026
krassx added a commit that referenced this pull request Nov 4, 2026
Unity Mono portable pdb -> BMF upload (#86, #99), Windows self-update leftover sweep (#103), panic exit codes 1/50 (#98), self-replace 1.5.1 (#97), Windows self-update CI (#100, #102).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WeiJxQWhjhQvvURAjiDkti
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