Skip to content

[CI][Windows] Worktree helper scenario 28 reddens main: the forced 5s timeout lands in the checkout phase, not the hung git add #2425

Description

@Chris0Jeky

Docs Governance / Worktree Helper (Windows PowerShell) reddened main on 2026-09-03. The failing case is scenario 28, codex-505-fsmonitor-hidden-git-add-timeout, in scripts/git/Test-New-CodexIssueWorktree.ps1. It is not #2378 and it is not covered by #1635 or #2400.

Occurrence

  • Run 33730061189, job 100567701501, branch main, head e1ea14fad40885a53907e8e8be762dc235c9e318 (the merge of PR Sanitize Ops CLI unexpected failure persistence #2422), 2026-09-03T07:49Z.
  • Failing step: 3, Validate detached-first worktree helper. Scenarios 1 through 27 passed; this is the next one.
  • Frequency: 1 failure in 20 observed runs of this job across the last 40 ci-required.yml runs (14 success, 1 failure, 1 cancelled, 4 still running at the time of counting). Rare, but it landed on main.

Failure

Index-hidden partial-registration cleanup did not explain its preservation decision.
Expected substring: <index contains assume-unchanged, skip-worktree, or fsmonitor-valid
                     entries that can hide modified data>
Actual output:
  git worktree add failed for '...\.worktrees\codex-505-fsmonitor-hidden-git-add-timeout'
  from 'origin/main' (exit code -1). Git: Git command timed out after 5 seconds; its
  helper-owned process tree was terminated and reaped. HEAD is now at 24695b8
  Preparing worktree (detached HEAD 24695b8)
  Updating files: 33% (2/6) ... 100% (6/6), done.

Thrown from Test-New-CodexIssueWorktree.ps1:265 via the assertion at scenario 28.

Mechanism

This scenario deliberately forces a timeout: it passes -GitCommandTimeoutSeconds 5 (against the helper's default of 45 at New-CodexIssueWorktree.ps1:14) and installs a hook fixture that hangs git add. The intent is that git worktree add times out while the hook is hanging, leaving a partial registration whose index carries assume-unchanged / skip-worktree / fsmonitor-valid entries. The helper's cleanup should then detect those, preserve rather than delete, and say why. The assertion checks for that explanation.

The scenario therefore depends on an unstated timing assumption: that 5 seconds is comfortably more than the checkout takes and comfortably less than the hung git add takes.

On this run the first half of that assumption broke. The captured Git output shows the checkout ran to Updating files: 100% (6/6), done., so the 5 second budget was consumed by the checkout itself rather than by the hook. The timeout landed at the wrong phase, the index-hidden cleanup path that emits the explanation was never reached, and the assertion failed against the generic timeout message.

So the helper is not obviously wrong here. The test's timing assumption is what does not hold on a slow Windows runner.

Relationship to #2378

Same family, different budget and different script, and it should not be folded in. #2378 is scripts/ci/dev-up.test.mjs on the Frontend Unit (windows-latest) leg, where a hardcoded 20 s spawnSync budget at :774 is simply too small for the work. Here the budget is deliberately small and the defect is that its landing point is timing-dependent. A fix to one does nothing for the other.

The common thread is worth naming, because it is now three separate places: hosted Windows runners are slow enough that fixed Git and process budgets written against a fast machine produce spurious reds. #2378 and this issue are two instances; #2157 is arguably a third.

Suggested fix

Make the timeout land deterministically at the hook rather than relying on the checkout being fast relative to a fixed 5 seconds. Options, in rough order of preference:

  1. Have the hook signal readiness (touch a canary the test waits on) and only start the constrained-timeout Git invocation after the checkout phase has completed, so the budget can only be consumed by the hang.
  2. Size the budget from an observed baseline (measure an unhung git worktree add in the same fixture, then set the constrained budget below the hang but above that baseline) instead of hardcoding 5.
  3. Assert on the cleanup's preservation behaviour directly (registration retained, populated target retained, guard bytes intact) and treat the explanation substring as a secondary assertion, so a mistimed timeout fails with a message that says the timeout landed in the wrong phase.

Option 3 alone would turn this from a spurious red into a clear diagnostic even if the timing still drifts, and it is the cheapest.

Please do not simply raise the 5 to a larger number: that widens the window in which the checkout fits, but it also widens the window in which the hung git add might itself complete, so it trades one flake for another without making the landing point deterministic.

Why this matters beyond the flake

docs/REVIVAL_PLAN.md:50 makes "main green" part of the v0.3.0 exit gate. Two distinct Windows-lane failures reddened main within four hours on 2026-09-03: run 33713409999 at 468d76dc8 (Frontend Unit (windows-latest), recorded on #2378 and #1898) and this one. Neither is tracked as a release blocker today. Whatever the burn-down list says, the gate clause is measured against the branch, not the issue list.

Not verified

I read the job log and the two PowerShell scripts. I did not run the suite locally, did not reproduce the failure, and did not measure how long an unhung git worktree add takes in that fixture on a hosted Windows runner, which is the number option 2 would need. I checked 20 runs of this job, not the full history, so the 1-in-20 rate is a sample and not a base rate. I did not check whether this scenario has failed before 2026-09-03.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Priority IIThe active direction's next tranche: wedge capabilities, significant defects, near-term hardening.bugSomething isn't workingciCI/CD pipeline, workflow, and build infrastructure changes.testingTest coverage, harnesses, regression prevention, and verification pipeline work.

    Projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions