JetBrains / JetBrains/thinkrail

The host's own git reads re-arm the repo-metadata watcher: a self-sustaining `fsChanged` loop spawning ~45 git processes/s until Bun crashes

Open Beginner friendly
#438 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
TypeScript
Stars
467
Forks
37
Avg merge
1d 56m
Merged PRs (30d)
141

Description

## Description

The host's own read-only git calls can re-arm the repo-metadata watcher, and every arming makes every client re-read the workspace with a fan-out of git subprocesses. While something keeps `.git/index` racy (an agent editing files in a terminal, for example), the cycle sustains itself at the watcher's cadence: `git status` / `git diff` rewrite the index → the unfiltered git-dir watcher fires → 300 ms later a pathless `fsChanged` is published → clients re-read (Changes panel `git status` + diff, projects rail `workspace.list` = one `git diff --shortstat` **per workspace**, `refreshUserOwnedWorkspace`) → `git status` / `git diff` rewrite the index again.

In the desktop app this ended in a crash of the bundled Bun. The crash itself is a Bun 1.3.14 bug (a segfault inside the runtime), but what tripped it was the churn: Bun's own diagnostics counted **24,455 subprocess spawns in 539 s** (~45/s) before it died.

Every ingredient is on `main`:

- `packages/server/src/watch/watch.ts` — the git-dir watcher is non-recursive and deliberately unfiltered, so an `index` rewrite counts as a metadata change (the spec explains why paths cannot be matched reliably; the trade-off is that a status refresh looks like a commit).
- `packages/server/src/host/server.ts` — `setRepoMetaPublisher` runs `refreshUserOwnedWorkspace` and then publishes a pathless `fsChanged`, which makes every client re-read.
- `packages/server/src/workspaces/workspaces.ts` — `workspace.list` runs `git diff --shortstat` once per workspace on every re-read.
- `packages/server/src/git/gitExec.ts` — `nonInteractiveGitEnv` sets only `GIT_TERMINAL_PROMPT=0`; nothing stops `status` / `diff` from opportunistically rewriting `.git/index`.

## Steps to reproduce

1. Open a project with several workspaces (so the rail has several rows to compute diff stats for) and expand the Files tree and the Changes panel.
2. Keep the worktree busy for a few minutes — e.g. run Claude Code or any tool that edits files in a terminal tab.
3. Watch the host's subprocess rate (`ps` / `fs_usage`, or note `spawn(N)` in Bun's crash banner). On macOS 26 with the desktop build, the bundled Bun 1.3.14 eventually crashes.

## Expected behavior

A read-only git command issued by the host must not look like a repository change to the host, and one file-system change batch should cost a bounded, small number of subprocesses.

## Actual behavior

~45 git subprocesses per second sustained for the length of the session, then:

```
Bun v1.3.14 (0d9b296a) macOS Silicon
macOS v26.6.2
Features: ... spawn(24455) ... workers_spawned
Elapsed: 539272ms | User: 27580ms | Sys: 16725ms
RSS: 0.24GB | Peak: 0.49GB

panic: Segmentation fault at address 0x10
oh no: Bun has crashed. This indicates a bug in Bun, not your code.
https://bun.report/1.3.14/Ma10d9b296iSuhooC_25u4oB25u4oB2/6yfu5mlxB+tqwHmvinlB__A2AgB

Child process terminated by signal: 5
```

The macOS crash report (`bun-2026-09-07-075544.ips`) shows `EXC_BREAKPOINT` / `SIGTRAP` on the `Worker` thread — which, under Electrobun, is the thread that runs the whole host (`new Worker(appEntrypointPath)` in `electrobun/dist/main.js`).

Suggested fix, smallest first:

1. Add `GIT_OPTIONAL_LOCKS=0` to `nonInteractiveGitEnv` (git then skips the opportunistic index refresh for read-only commands), so the host's own reads can never re-arm the metadata nudge. One line plus a spec note.
2. Consider computing rail diff stats less eagerly than once per workspace per `fsChanged`.
3. Separately, this is a Bun 1.3.14 bug; an Electrobun release bundling a newer Bun would remove the crash even if the churn stays.

## Environment

- OS: macOS 26.6.2 (Apple Silicon)
- Bun version (`bun --version`): 1.4.0 on the machine; the desktop app bundles Electrobun 1.18.1's custom Bun 1.3.14, which is what crashed
- Node version (`node --version`): v26.8.1
- ThinkRail version / commit: `main` at a3b91d7e (2026-09-06); observed on a fork branch that adds a `git check-ignore` per directory listing, which only makes each turn of the cycle more expensive — the cycle itself is unchanged from `main`

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Contributor guide

Open the contributing guide

Research direction

Start in packages/server/src/git/gitExec.ts and read nonInteractiveGitEnv, then review the watcher behavior in packages/server/src/watch/watch.ts and the related spec note. The smallest completion criterion is that host-issued read-only git commands no longer re-arm repository metadata watching; use the issue's reproduction to verify subprocess churn is bounded.

Written by the indexing model from the issue text.

Assessment

Tech stack
bun, git, typescript
Domain
backend, devtools, performance
Issue type
Bug
Difficulty
2/5
Estimated time
1-3 hours
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
72/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.