Skip to content

fix(git): a git timeout is said, never read as clean or not-a-repo (#1250 row 11) - #1429

Merged
Juliusolsson05 merged 6 commits into
mainfrom
fix/git-timeout-not-clean
Sep 27, 2026
Merged

Juliusolsson05 merged 6 commits into
mainfrom
fix/git-timeout-not-clean

Conversation

@Juliusolsson05

@Juliusolsson05 Juliusolsson05 commented Sep 27, 2026 •

Copy link
Copy Markdown
Owner

Refs #1250 (row 11). #1250 is a batch issue, so the other rows stay open.

Problem

Every git failure in src/main/ipc/git.ts returns '' by a documented contract, and only a missing binary was ever told apart (#495 A5). In a large repo, or on a busy disk, a command that hit the runner's 5 s timeout therefore read as "no output":

  • Worktrees panel (a cleanup tool): a timed-out git status made a dirty worktree read CLEAN. A timed-out git cherry read as zero patch-unique commits, making the row "patch-equivalent", a cleanup suggestion. The result was cached for 30 s.
  • Worktrees panel / GitBar: a timed-out list or branch probe read "Not a Git repository."
  • GitBar: a timed-out diff or log showed a partial, clean-looking status.

Change

  • A timeout trace. runGitCommand recognises execFile's timeout (killed with SIGTERM) and marks the AsyncLocalStorage trace captured when the command was queued. '' is still returned, so no existing caller changes.
  • Worktree rows, each under its own trace:
    • a timed-out git status counts as dirty;
    • any timeout marks the row statusTimedOut and category review (never a cleanup category);
    • a list with a timed-out row is not cached.
  • git:worktrees, git:worktree-status and git:status: a timed-out probe answers { ok: false, gitMissing, timedOut: true }. A GitBar status with a later timeout answers incomplete: true.
  • Renderer:
    • GitBar and the Worktrees panel say "Git took too long to answer here. It will try again." instead of "Not a Git repository.";
    • GitBar marks an incomplete status;
    • a timed-out row shows "status unknown (git timed out)";
    • the copyable worktree dump says the same.
  • worktrees.read (control) reports gitTimedOut.
  • Other consumers of the plain list (the conversation-picker family, worktree activity, the agent-activity repo root, history context) are split into bug(git): other consumers still read a timed-out worktree list as an empty family #1430.

Plan: docs/plans/2026-09-27-git-timeout-not-clean.md.

Tests

  • New src/main/ipc/git.timeout.test.ts: the real handlers and runner, with execFile replaced to time out chosen commands the way Node does.
    • A timed-out row status reads dirty and review; a timed-out cherry is never patch-equivalent; that row is not cached.
    • A timed-out list and a timed-out branch probe answer timedOut; a timed-out log gives incomplete.
    • 5 of 6 are red on the base; the no-cache case passes there only because nothing was marked.
  • New GitBar.renderer.test.tsx and additions to WorktreesBar.renderer.test.tsx: the timeout copy, the incomplete note and the row chip. All red on the base.
  • New worktrees/control.renderer.test.ts: worktrees.read, through execute, tells a timeout from "not a repository".

Verification

  • rm -rf .tsc-out; npx tsc -b: clean.
  • NODE_ENV=test npx vitest run src/main/ipc src/renderer/src/features/git src/renderer/src/features/worktrees: 93/93.
  • Review round 1: the disposition is in the PR comments.
  • The app was not launched.

🤖 Generated with Claude Code

Juliusolsson05 and others added 3 commits September 27, 2026 06:13
…1250 row 11)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…-a-repo (#1250 row 11)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…row 11)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Juliusolsson05

Copy link
Copy Markdown
Owner Author

Review disposition, round 1: reviewers a and b (head edc5216e)

Verdicts: a FIX-BEFORE-MERGE, b FIX-BEFORE-MERGE. c's report is pending.

Finding Disposition
a1 / b1: worktrees.read dropped the timeout, so an agent read a slow repo as "not a repository" Fixed. It reports gitTimedOut, and the description says so. The test goes through execute (output schema validated) with the real loadWorktreeDump. It fails on the previous head and kills b's surviving mutation.
b2: the conversation-picker family, worktree activity and the agent-activity repo root still read a timed-out list as empty Split into #1430. These are other features' consumers of the plain list; each self-heals on the next call. The issue names each one and the fix direction (listWorktreesForCwdDetailed exists after this PR).
b3: renderer history context passes [] on a timed-out catalog Split into #1430 (same class; a live catalog refresh may correct it).

Verification: npx tsc -b is clean; the new control test passes, 1/1.

🤖 Generated with Claude Code

… stays main (#1429 review c)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Juliusolsson05

Copy link
Copy Markdown
Owner Author

Reviewer c (FIX-BEFORE-MERGE on test gaps; it reviewed 6312be56, before the control fix): addressed in c8e858c1.

  • c1: an ordinary git failure (exit 128, not killed) is now pinned as not a timeout for git:status and git:worktrees. The "every failure is a timeout" mutation fails.
  • c2: the gitTimedOut producer path is covered by the control test in edc5216e, through the real loadWorktreeDump (that mutation fails there).
  • c3: a timed-out main row keeps main; the unconditional-review mutation fails.
  • c4: the !timedOut in the list cache rule is commented as defensive only.
  • c5: re-running the fan-out on every poll while a repo keeps timing out is the intended trade (a wrong answer is not cached for 30 s).

git.timeout.test.ts: 8/8. Verification a and b follow.

🤖 Generated with Claude Code

#1429 verification a)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Juliusolsson05

Copy link
Copy Markdown
Owner Author

Verification: a FIX-BEFORE-MERGE (a test gap), b MERGE-READY. Addressed in 1a379f71. a's queue-attribution invariant is committed: eight busy commands hold every runner slot; a ninth request, whose branch probe times out, waits in the queue and runs from another request's drain. It still answers timedOut: true, and the eight report no timeout. The drain-time mutation fails it. git.timeout.test.ts: 9/9.

Round count: round 1 and verification are done, so the review is capped. The PR waits for CI and the manager check.

🤖 Generated with Claude Code

@Juliusolsson05

Copy link
Copy Markdown
Owner Author

Correction to the reviewer c disposition (manager-verified at 1a379f7).

c8e858c does not fix c1 or c3. It adds tests and one comment, because the code was already correct. Each finding was a test gap:

  • c1 (major): pinned only. The test "keeps 'not a repository' for a plain non-repository" (exit 128, not killed) fails under c's mutation M1b.
  • c2 (major): fixed in edc5216 (control.ts had dropped gitTimedOut). The test "tells a timeout apart from 'not a repository'" fails with control.ts at 6312be5, and under M14.
  • c3 (minor): pinned only. The test "keeps a main row as main when its status timed out" fails under M2b.
  • c4 (minor): the !timedOut cache guard is unreachable, so M5 survives. It is documented as defensive in git.ts. Accepted residual.
  • c5: intended trade-off, as stated before.

Residual: M15 survives. The timed-out status line in formatWorktreeDump is not caught by any test. If that line regressed, the worktree dump would lose its "git timed out" wording while the data still carries gitTimedOut.

🤖 Generated with Claude Code

Juliusolsson05 added a commit that referenced this pull request Sep 27, 2026
@Juliusolsson05
Juliusolsson05 merged commit db35dbf into main Sep 27, 2026
2 checks passed
@Juliusolsson05
Juliusolsson05 deleted the fix/git-timeout-not-clean branch September 27, 2026 15:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

class:C3-silent-failure The app knows it failed and does not say sev:P3 Minor type:bug Something works wrong

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant