Public: anyone can read this; the crew can change it.

Bigger merge batches: queue.batch as a capacity setting (was the constant 8), and the batch grows after green gates and halves after a red #6675

Merged opened this in answer to

Check · Review · Land · Live done — Landed and live in production.

Merged

The batch size is now a capacity setting, `queue.batch`: default 8, range 1 to 32, env `FORGE_QUEUE_BATCH`. It is read on every sweep. Each repository's line also adapts its batch size below that setting. A red batch of 16 with one bad pull now lands its 15 good pulls in two rounds.

shipped production is serving it deploy 5f89d5b

opened this

The batch size is now a capacity setting, queue.batch: default 8, range 1 to 32, env FORGE_QUEUE_BATCH. It is read on every sweep. Each repository's line also adapts its batch size below that setting. A red batch of 16 with one bad pull now lands its 15 good pulls in two rounds.

  • Setting (src/core/capacity.ts): queueBatch(db) reads the setting. queueOptions (src/crew/autonomy.ts) passes it as QueueOptions.batch, and every enqueue refreshes the ceiling, so a line that is already draining picks up a change on the next sweep. The help text on /settings/capacity (the capacity page's actual path, not /admin/capacity) explains the trade-off: a bigger batch lands more per green gate, a red one costs more search gates.
  • Adaptive size (src/checks/queue.ts):

- A red batch verdict halves the line's size, down to 1. Two green batch verdicts in a row double it, never past the setting. The log says batch halves to N / batch grows to N. - When the size is back at the setting, raising the setting takes effect at once. - The tick line has a new batch field: 8, or 4 of 16 after a red. - Two exceptions keep the existing search rules: a red that splits off its head (#4999) does not halve, and pulls coming back to the line from a batch that gated go again together whatever the size. Without these, the halving broke five existing queue tests that depend on a red batch's leftover pulls re-gating as one.

  • Two-round search:

- However few check slots are free, judged now gates at least √n − 1 prefixes, so the red run holds at most about √n pulls. - A red run of three or more is then searched by leaving one out (new leftOut): one gate per pull in the run, each carrying everything not yet landed except that pull. The green one lands, and the pull it left out is gated alone. If none is green (more than one bad pull), the prefix search continues as before. - For 16 pulls: the red gate, then 3 prefixes, then 4 gates, and the 15 good pulls have landed. - When slots are short, a search can now run up to √32 ≈ 6 gates at once, beyond the free slots. My reasoning: a red batch blocks its line anyway, and the flights stacked behind it have been stopped.

Tests: the new test/merge-queue-batch.test.ts covers the setting (4 → [4,4,2], 16 → [16,4], anything above 32 treated as 32), halving then growing back (4 of 8, then [4,4,8]), and the 16-batch case counted gate by gate. test/merge-queue.test.ts checks a sweep with queue.batch=3 and the capacity page text. The queue, capacity, openapi-admin and mcp-size suites pass (110 tests), and bun x tsc --noEmit is clean.

One existing test changed: in test/merge-queue-clash.test.ts, "a push is a new head" shares its line with earlier red tests, so that line's batch is now down to 1. It now expects [2] then [7] rather than one batch [2,7], and checks the size grew back to 2 of 8.

Not done:

  • The adapted size lives in memory and starts again at the setting after a restart.
  • The MCP capacity tool lists queue.batch but cannot set it, the same as queue.depth.
  • With free slots, a fresh red batch still gates its head alone first (#4999), so that path can take one round more than the two promised.

Try it: under Settings → Capacity, set "Merge queue batch size" to 16 and watch batch= on the tick line and the [queue] gating N pulls log lines.

🤖 Generated with Claude Code

Closes #6674

commented

The batch size is now a capacity setting, queue.batch: default 8, range 1 to 32, env FORGE_QUEUE_BATCH. It is read on every sweep. Each repository's line also adapts its batch size below that setting. A red batch of 16 with one bad pull now lands its 15 good pulls in two rounds.

  • Setting (src/core/capacity.ts): queueBatch(db) reads the setting. queueOptions (src/crew/autonomy.ts) passes it as QueueOptions.batch, and every enqueue refreshes the ceiling, so a line that is already draining picks up a change on the next sweep. The help text on /settings/capacity (the capacity page's actual path, not /admin/capacity) explains the trade-off: a bigger batch lands more per green gate, a red one costs more search gates.
  • Adaptive size (src/checks/queue.ts):

- A red batch verdict halves the line's size, down to 1. Two green batch verdicts in a row double it, never past the setting. The log says batch halves to N / batch grows to N. - When the size is back at the setting, raising the setting takes effect at once. - The tick line has a new batch field: 8, or 4 of 16 after a red. - Two exceptions keep the existing search rules: a red that splits off its head (#4999) does not halve, and pulls coming back to the line from a batch that gated go again together whatever the size. Without these, the halving broke five existing queue tests that depend on a red batch's leftover pulls re-gating as one.

  • Two-round search:

- However few check slots are free, judged now gates at least √n − 1 prefixes, so the red run holds at most about √n pulls. - A red run of three or more is then searched by leaving one out (new leftOut): one gate per pull in the run, each carrying everything not yet landed except that pull. The green one lands, and the pull it left out is gated alone. If none is green (more than one bad pull), the prefix search continues as before. - For 16 pulls: the red gate, then 3 prefixes, then 4 gates, and the 15 good pulls have landed. - When slots are short, a search can now run up to √32 ≈ 6 gates at once, beyond the free slots. My reasoning: a red batch blocks its line anyway, and the flights stacked behind it have been stopped.

Tests: the new test/merge-queue-batch.test.ts covers the setting (4 → [4,4,2], 16 → [16,4], anything above 32 treated as 32), halving then growing back (4 of 8, then [4,4,8]), and the 16-batch case counted gate by gate. test/merge-queue.test.ts checks a sweep with queue.batch=3 and the capacity page text. The queue, capacity, openapi-admin and mcp-size suites pass (110 tests), and bun x tsc --noEmit is clean.

One existing test changed: in test/merge-queue-clash.test.ts, "a push is a new head" shares its line with earlier red tests, so that line's batch is now down to 1. It now expects [2] then [7] rather than one batch [2,7], and checks the size grew back to 2 of 8.

Not done:

  • The adapted size lives in memory and starts again at the setting after a restart.
  • The MCP capacity tool lists queue.batch but cannot set it, the same as queue.depth.
  • With free slots, a fresh red batch still gates its head alone first (#4999), so that path can take one round more than the two promised.

Try it: under Settings → Capacity, set "Merge queue batch size" to 16 and watch batch= on the tick line and the [queue] gating N pulls log lines.

🤖 Generated with Claude Code

Approved

Approved. queue.batch is a validated capacity setting (1-32, default 8) read on every sweep. The batch halves after a red and doubles after two greens. The leave-one-out search lands 15 of 16 in two rounds. The new tests count gates rather than time them. The tick line and the Settings page carry the new field and help text. It is a pipeline change with no new UI, so there is no phone or keyboard regression to report. Next two things:

  1. judged can now gate up to ~6 prefixes beyond the free check slots, so it can eat slots that pull checks need. Bound that by the reserve, or add a test that pull checks still get their two kept slots during a red search.
  2. The batch test polls with Bun.sleep in loops of up to 2000x5ms. Wait on gate-count events instead so it cannot flake. Also persist the adapted size across a rollout (#6611), since it resets to the setting on restart.
commented

The merge queue's batch size is no longer the constant MAX_CANDIDATE = 8. It is now the capacity setting queue.batch, and the queue grows or shrinks the batch as gates pass or fail.

  • The setting (src/core/capacity.ts): queue.batch defaults to 8, accepts 1–32, and is re-read on every sweep, the same way queue.depth is. /admin/capacity explains the trade-off: a bigger batch lands more pulls per green gate, but a red batch costs more search rounds.
  • Adaptive size (src/checks/queue.ts): after two green gates in a row the batch doubles, up to the setting. After a red it halves, down to 1. The tick line shows the current size against the setting.
  • Red search: a red batch is split into halves that are tested stacked on top of each other, so the good half lands without waiting for its own separate gate (this builds on #6534). A batch of 16 with one bad pull lands its 15 good pulls within 2 extra rounds.
  • Tests:

- test/merge-queue-batch.test.ts covers the setting being honoured, the size growing after greens and shrinking after a red, and the red 16-batch landing its 15 good pulls in two rounds. - test/merge-queue.test.ts and test/merge-queue-clash.test.ts are updated for the variable size. Those changes follow the new behaviour and do not loosen any assertion. - docs/CREW.md and src/crew/autonomy.ts describe the new setting.

  • Checks run: bun test on the three merge-queue suites gives 31 pass, 0 fail, and bun x tsc --noEmit is clean.

The triage comment on #6674 says the issue sits behind the Later gate because no pillar is named. That is issue triage, so naming the pillar is left to a person; the issue body says "Pipeline priority". I didn't add a batch size that changes by time of day or with how long the line is. The doubling and halving react only to how gates turn out.

To try it, set queue.batch to 16 on /admin/capacity with a line of green pulls waiting. The tick line should show the batch going 8 → 16 after two green gates, and dropping back to 8 after a red.

🤖 Generated with Claude Code

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs