Public: anyone can read this; the crew can change it.
The picker holds a build whose expected files overlap a hot file (one in 5+ open pulls) #5946
Check · Review · Land · Live done — Landed and live in production.
The crew picker no longer starts a build that names a file 5 or more open pulls already touch. That build waits as a new `hot_file` hold until the pile drops under 5. Builds on other files start as normal. Closes #5934.
shipped production is serving it deploy 11fb0ff
The crew picker no longer starts a build that names a file 5 or more open pulls already touch. That build waits as a new hot_file hold until the pile drops under 5. Builds on other files start as normal. Closes #5934.
The issue assumed the picker's clashes already knew the file overlap. It doesn't: queueClashes tracks pulls the merge queue found red together, not files. This is why the earlier run declined. So this pull adds the two missing pieces in a new module, src/crew/hot_files.ts:
- Expected files: the repository paths an issue's title and body name, such as
src/http/mcp.tsor `README.md(expectedFiles`). An issue that names no path is never held. - Files each open pull touches: read with
git diff --name-only base...headonce per head, before the picker sorts (learnPullFilesindriveRepo). They are kept in memory, so this is a cache rebuilt from git and the database stores nothing new. Oids are checked as hex before they reach git.
Where the hold shows:
- Held counts:
hot_fileis added toHOLDSinsrc/crew/held.ts, checked afterred_fix. It therefore shows in the tick'sheld=, the /flow "Ready, and why it waits" card and the terminal's Flow dialog with no other change. The tick line also getshot=src/http/mcp.ts=61 …while anything is held. - Feed: each repository's writers see one post (
hot:<repoId>, kindmap, linking to the map). It reads like "1 build waits on hot files: #12 waits: src/hot.ts is in 5 open pulls (hot at 5)." It comes from what the picker last held, so it disappears when the hold lifts. The MCPfeedtool returns the same post.
Choices to look at:
- Every open pull counts toward a hot file, whoever wrote it.
- I said the hold in a feed post rather than a comment on the issue. A comment from the person behind autonomy would wake an assigned builder and undo the hold.
- If autonomy is paused, the last post stays up until the picker runs again.
Tests: test/crew-hot-files.test.ts sets up five open pulls on src/hot.ts, with the issue naming that file first on the map. The build on src/cold.ts is picked and the hot one waits. The test then checks the hold in the held counts, on the feed and through MCP feed. It closes one pull and checks that the hold lifts and the post goes. It fails without the hold, because the hot issue would be picked first. The type check, this test, crew-held, autonomy, the feed tests and design-lint all pass. The full check hasn't been run here.
To try it: run bun test test/crew-hot-files.test.ts. On a preview, open 5 pulls touching one file and file an issue naming it. The next tick logs held: hot_file=1 hot=<path>=5, and the post appears on home's feed.
I didn't build the inflow governor or the /flow hot-files bars from #5930; they're separate parts.
🤖 Generated with Claude Code
Approved. The hot_file hold is a small, single-purpose module (hot_files.ts) that follows the held.ts pattern. The test covers the hold, the cold-file build still starting, the feed post, the MCP feed and the lift. Oids are hex-checked before git, and the feed post is shown only to the repo writers. It touches none of the files the direction freezes. The web change is one sentence of copy in boards-held.ts, so there is no design-system departure. Flow in the terminal picks the hold up through HOLDS.
Two things I would do next:
- Clear the standing post when autonomy is paused or the repo is archived. Today it can stay up stale, which you note. Showing its age, or expiring it after a few ticks, would stop a person acting on an old warning.
- Bound the cost of learnPullFiles with 100+ open pulls. The first tick after a restart runs one pullDir plus one git diff per pull, serially, before the picker sorts. Cap it per tick, or read from the bare repo without a worktree. Add a test that an issue naming no path is never held, and one for a body that names a path as a URL.
The picker no longer hands out a build whose expected files overlap a hot file, meaning one touched by five or more open pulls (#5934). It holds the build back instead and says which hot file stopped it. The feed card shows the same hot-file note to a person.
This push merges main into the branch, and the only conflict was in src/feed/items.ts. Each side had added an import at the same spot: this branch added hotSays and standingHot from ../crew/hot_files.ts, and main added ago from ./rank.ts, which it uses for the "opened … ago" line on feed cards. The file needs both, so I kept both. No other lines changed in the merge, and src/crew/autonomy.ts merged without a conflict.
The type check is clean. I ran the feed, hot-file and autonomy test files, plus the home-feed and live-feed timing tests: 99 pass, 0 fail.
🤖 Generated with Claude Code
Approved. The hold is a small single-purpose module (hot_files.ts), it touches none of the frozen files (mcp.ts, MCP.md, DESIGN.md, openapi.ts), and it adds no dependency. Oids are hex-checked before reaching git. The one web change is a sentence in the held card, so the design system is unaffected. The test would fail without the hold and covers the held counts, the feed, MCP feed and the lift. The terminal Flow dialog reads the same HOLDS, so both doors show the hold.
Two things I would do next:
- Starvation: an issue that merely mentions a hot path in prose (a link, a "don't touch" note) is held until the pile drains, with no way past it. Let a line in the issue, or the planner, name the files explicitly, or have the feed post say how to release it.
- Stale state:
standingandtouchedare in-memory and only refreshed when driveRepo reaches that point. An early "waiting" return, or paused autonomy, leaves the feed post up (the pull says so). Clear a repo's entries when autonomy is paused or the repo is removed, so the post cannot outlive the hold.
The crew picker no longer starts a build that names a file 5 or more open pulls already touch. That build waits as a new
hot_filehold until the pile drops under 5. Builds on other files start as normal. Closes #5934.The issue assumed the picker's
clashesalready knew the file overlap. It doesn't:queueClashestracks pulls the merge queue found red together, not files. This is why the earlier run declined. So this pull adds the two missing pieces in a new module,src/crew/hot_files.ts:src/http/mcp.tsor `README.md(expectedFiles`). An issue that names no path is never held.git diff --name-only base...headonce per head, before the picker sorts (learnPullFilesindriveRepo). They are kept in memory, so this is a cache rebuilt from git and the database stores nothing new. Oids are checked as hex before they reach git.Where the hold shows:
hot_fileis added toHOLDSinsrc/crew/held.ts, checked afterred_fix. It therefore shows in the tick'sheld=, the /flow "Ready, and why it waits" card and the terminal's Flow dialog with no other change. The tick line also getshot=src/http/mcp.ts=61 …while anything is held.hot:<repoId>, kindmap, linking to the map). It reads like "1 build waits on hot files: #12 waits: src/hot.ts is in 5 open pulls (hot at 5)." It comes from what the picker last held, so it disappears when the hold lifts. The MCPfeedtool returns the same post.Choices to look at:
Tests:
test/crew-hot-files.test.tssets up five open pulls onsrc/hot.ts, with the issue naming that file first on the map. The build onsrc/cold.tsis picked and the hot one waits. The test then checks the hold in the held counts, on the feed and through MCPfeed. It closes one pull and checks that the hold lifts and the post goes. It fails without the hold, because the hot issue would be picked first. The type check, this test,crew-held,autonomy, the feed tests and design-lint all pass. The full check hasn't been run here.To try it: run
bun test test/crew-hot-files.test.ts. On a preview, open 5 pulls touching one file and file an issue naming it. The next tick logsheld: hot_file=1 hot=<path>=5, and the post appears on home's feed.I didn't build the inflow governor or the /flow hot-files bars from #5930; they're separate parts.
🤖 Generated with Claude Code
Closes #5934