diff --git a/.github/workflows/sweep.yml b/.github/workflows/sweep.yml index 860a76c389..236dcd9480 100644 --- a/.github/workflows/sweep.yml +++ b/.github/workflows/sweep.yml @@ -74,7 +74,7 @@ on: shard_count: description: "Parallel shards (capped by config/automation-limits.json)" required: false - default: "22" + default: "28" item_number: description: "Optional single issue/PR number to review" required: false diff --git a/README.md b/README.md index 4b5fecbfbd..82b64e6d19 100644 --- a/README.md +++ b/README.md @@ -554,7 +554,7 @@ source ~/.profile corepack enable pnpm install pnpm run build -pnpm run plan -- --target-repo openclaw/openclaw --batch-size 5 --shard-count 22 --max-pages 250 --codex-model internal --codex-reasoning-effort high +pnpm run plan -- --target-repo openclaw/openclaw --batch-size 5 --shard-count 28 --max-pages 250 --codex-model internal --codex-reasoning-effort high pnpm run review -- --target-repo openclaw/openclaw --target-dir ../openclaw --batch-size 5 --max-pages 250 --artifact-dir artifacts/reviews --codex-model internal --codex-reasoning-effort high --codex-timeout-ms 600000 pnpm run apply-artifacts -- --target-repo openclaw/openclaw --artifact-dir artifacts/reviews --skip-dashboard pnpm run audit -- --target-repo openclaw/openclaw --max-pages 250 --sample-limit 25 --update-dashboard @@ -611,13 +611,13 @@ default, subject to the selected repository profile; pass `target_repo`, `apply_kind=issue`, or `apply_kind=pull_request` to narrow a manual run. Scheduled runs cover the configured product profiles. `openclaw/openclaw` runs -normal backfill every 5 minutes with up to 12 review shards when the system is +normal backfill every 5 minutes with up to 28 review shards when the system is quiet; `openclaw/clawhub` runs on offset review/apply/audit crons so its reports live under `records/openclaw-clawhub/` without colliding with default repo records. `openclaw/clawsweeper` has a scheduled read-only audit row and is available for manual and event self-review smoke tests. Broad hot-intake sweeps -cap scheduled fan-out at 11 one-item shards per run when quiet; manual normal -backfill can use up to 22 shards, while exact event reviews still use one shard. +cap scheduled fan-out at 16 one-item shards per run when quiet; manual normal +backfill can use up to 28 shards, while exact event reviews still use one shard. Normal review, hot intake, and commit review are background lanes, so they shrink automatically while repair or exact-item work is active. Throughput defaults live in @@ -626,18 +626,18 @@ is active. Throughput defaults live in ### Worker Budget ClawSweeper has one main capacity knob: -`config/automation-limits.json` -> `workers.max`. The current value is `32`. -Lane limits are derived from that number: normal review defaults to 22 shards -for manual/backstop runs, scheduled normal review gets up to 12 after reserves, -hot intake up to 11 shards, commit review 1 commit per page, and existing -repair/issue implementation lanes use 40% of `workers.max`, currently 12 live +`config/automation-limits.json` -> `workers.max`. The current value is `48`. +Lane limits are derived from that number: normal review defaults to 28 shards +for manual/backstop runs, scheduled normal review gets up to 28 after reserves, +hot intake up to 16 shards, commit review 2 commits per page, and existing +repair/issue implementation lanes use 40% of `workers.max`, currently 19 live workers. Imported gitcrawl cluster repair allows 2 live workers by default. Exact-item review, repair, and issue implementation are priority work; normal review, hot intake, and commit review are background work and automatically yield when priority work is active. Exact-item runs use a durable Worker queue that coalesces item deliveries, leases at most 4 concurrent reviews, and admits at most one active exact review per target repository. Other lanes retain the -checked-in 32-worker scheduling model. +checked-in 48-worker scheduling model. Use `workers.max` first when turning total Codex usage up or down; use `lanes.repair.cluster_max_live_runs` to tune the imported legacy cluster-repair lane separately, and individual environment overrides only for temporary diff --git a/config/automation-limits.json b/config/automation-limits.json index daebe4fe4e..2f5d8b1c59 100644 --- a/config/automation-limits.json +++ b/config/automation-limits.json @@ -1,6 +1,6 @@ { "workers": { - "max": 32, + "max": 48, "reserve_for_interactive": 8, "expansion_reserve": 12, "minimum_background": 4 diff --git a/dashboard/worker.ts b/dashboard/worker.ts index 611b6bfe84..9e39690b66 100644 --- a/dashboard/worker.ts +++ b/dashboard/worker.ts @@ -71,6 +71,7 @@ const CLOSED_STATS_PAGE_LIMIT = 10; const DEFAULT_CLAWSWEEPER_BOT_LOGINS = ["clawsweeper[bot]", "openclaw-clawsweeper[bot]"]; const GITHUB_TIMEOUT_MS = 4500; const DEFAULT_STALE_QUEUED_WORKFLOW_MS = 6 * 60 * 60 * 1000; +const DEFAULT_WORKER_BUDGET = 48; const DEFAULT_EXACT_REVIEW_QUEUE_MAX_CONCURRENT = 4; const DEFAULT_EXACT_REVIEW_TARGET_MAX_CONCURRENT = 1; const DEFAULT_EXACT_REVIEW_DISPATCH_LEASE_MS = 10 * 60 * 1000; @@ -1240,7 +1241,7 @@ export function exactReviewQueueCapacity(env) { return Math.max( 1, Math.min( - 32, + DEFAULT_WORKER_BUDGET, numberFrom(env.EXACT_REVIEW_QUEUE_MAX_CONCURRENT, DEFAULT_EXACT_REVIEW_QUEUE_MAX_CONCURRENT), ), ); @@ -1633,7 +1634,7 @@ async function statusSnapshot(env) { .split(",") .map((value) => value.trim()) .filter(Boolean); - const budget = numberFrom(env.WORKER_BUDGET, 32); + const budget = numberFrom(env.WORKER_BUDGET, DEFAULT_WORKER_BUDGET); const [runs, completedRuns, filteredActiveRuns] = await Promise.all([ githubJson(env, `/repos/${repo}/actions/runs?per_page=100`).catch((error) => { errors.push(`workflow runs: ${error.message}`); diff --git a/dashboard/wrangler.toml b/dashboard/wrangler.toml index 1a2c42cbad..bb0ae0e91e 100644 --- a/dashboard/wrangler.toml +++ b/dashboard/wrangler.toml @@ -29,7 +29,7 @@ CLAWSWEEPER_REPO = "openclaw/clawsweeper" CLAWSWEEPER_APP_CLIENT_ID = "Iv23liOECG0slfuhz093" CLAWSWEEPER_CRABFLEET_URL = "https://crabfleet.openclaw.ai" TARGET_REPOS = "openclaw/openclaw,openclaw/clawhub,openclaw/clawsweeper,openclaw/fs-safe" -WORKER_BUDGET = "32" +WORKER_BUDGET = "48" WORKER_DETAIL_RUN_LIMIT = "128" WORKER_JOB_FETCH_CONCURRENCY = "12" WORKER_JOB_CACHE_TTL_SECONDS = "60" diff --git a/docs/commit-dispatcher.md b/docs/commit-dispatcher.md index 6bb50e9d6e..7ebb27f240 100644 --- a/docs/commit-dispatcher.md +++ b/docs/commit-dispatcher.md @@ -107,7 +107,7 @@ CLAWSWEEPER_COMMIT_REVIEW_SETTLE_SECONDS=60 Use `0` for settled manual backfills or a larger value during GitHub event lag incidents. -Commit review is a background lane. It defaults to 1 commit per workflow page +Commit review is a background lane. It defaults to 2 commits per workflow page when the system is quiet, but the receiver asks the central worker scheduler for capacity before each page. Active repair, exact-item review, and sweep work can lower the page size so commit review does not consume capacity needed by @@ -116,10 +116,10 @@ maintainer-visible work. The checked-in default comes from `openclaw/clawsweeper` only when the org has enough rate-limit headroom: ```text -CLAWSWEEPER_COMMIT_REVIEW_PAGE_SIZE=1 +CLAWSWEEPER_COMMIT_REVIEW_PAGE_SIZE=2 ``` -The receiver clamps this between 1 and 32. Setting the variable bypasses the +The receiver clamps this between 1 and 48. Setting the variable bypasses the dynamic default for that run; leave it unset when the central scheduler should decide. Large push ranges continue in later workflow pages. diff --git a/docs/commit-sweeper.md b/docs/commit-sweeper.md index eac44dbd17..d23f4dc436 100644 --- a/docs/commit-sweeper.md +++ b/docs/commit-sweeper.md @@ -89,13 +89,13 @@ by SHA/range rather than detaching the whole target repository at the commit. ## Scaling -Commit Sweeper is background work. It defaults to 1 commit per workflow page +Commit Sweeper is background work. It defaults to 2 commits per workflow page when the system is quiet, but the receiver asks the central worker scheduler for the effective page size before dispatching the matrix. Active repair, exact-item review, and sweep work can lower commit review to keep capacity available for maintainer-visible work. The checked-in default lives in `config/automation-limits.json`. The receiver clamps -`CLAWSWEEPER_COMMIT_REVIEW_PAGE_SIZE` between 1 and 32, then pages large ranges: +`CLAWSWEEPER_COMMIT_REVIEW_PAGE_SIZE` between 1 and 48, then pages large ranges: - select up to the configured page size - classify them cheaply diff --git a/docs/limits.md b/docs/limits.md index bbf64b7974..f707d6ba98 100644 --- a/docs/limits.md +++ b/docs/limits.md @@ -33,7 +33,7 @@ The mental model: | Name | Current | Meaning | | --- | ---: | --- | -| `workers.max` | 32 | Maximum global Codex worker budget used to derive lane limits. | +| `workers.max` | 48 | Maximum global Codex worker budget used to derive lane limits. | | `workers.reserve_for_interactive` | 8 | Worker slots background lanes leave open for exact/manual/urgent work. | | `workers.expansion_reserve` | 12 | Extra slots background lanes leave open for independently planned matrix expansion. | | `workers.minimum_background` | 4 | Target floor for background progress when enough global capacity is available. | @@ -43,10 +43,11 @@ The mental model: ## Derived Limits -Review, commit, and existing repair limits are intentionally percentages of +Review, commit, and existing repair limits are intentionally derived from `workers.max`; imported cluster repair has its own lane knob. With -`workers.max = 32`, normal review can use 22 workers, hot intake can use 11, -commit review can use 1 commit per page, existing repair lanes dispatch 12 +`workers.max = 48`, normal review can use 28 workers after the interactive and +expansion reserves, hot intake can use 16, +commit review can use 2 commits per page, existing repair lanes dispatch 19 live workers by default, and imported cluster repair dispatches two live workers by default. @@ -54,23 +55,24 @@ by default. | --- | ---: | --- | | `exact_review.concurrent_max` | 4 | Exact-item review admission cap, clamped to `workers.max`. | | `assist.default` | 10 | Maintainer assist job cap. | -| `review_shards.normal_default` | 22 | Quiet-system normal review shard ceiling. | -| `review_shards.normal_active_floor` | 9 | Minimum active normal review shards to keep queued for `openclaw/openclaw`. | -| `review_shards.hot_intake_default` | 11 | Quiet-system broad hot-intake review shard ceiling. | +| `review_shards.normal_default` | 28 | Quiet-system normal review shard ceiling. | +| `review_shards.normal_active_floor` | 14 | Minimum active normal review shards to keep queued for `openclaw/openclaw`. | +| `review_shards.hot_intake_default` | 16 | Quiet-system broad hot-intake review shard ceiling. | | `review_shards.exact_item_default` | 1 | Exact-item hot-intake shard count. | -| `review_shards.hard_cap` | 32 | Maximum accepted review shard count. | -| `commit_review.page_size_default` | 1 | Commits selected per commit-review page. | -| `commit_review.page_size_hard_cap` | 32 | Maximum commit-review page size. | -| `repair_live_runs.default` | 12 | Default live repair workflow run cap for manual dispatch/requeue/self-heal. | -| `repair_live_runs.hard_cap` | 32 | Absolute live repair run cap accepted by explicit CLI/env overrides with this config. | -| `repair_live_runs.automerge_default` | 12 | Live repair run cap for automerge comment-router dispatches. | -| `repair_live_runs.issue_implementation_default` | 12 | Live repair run cap for issue-to-PR implementation intake. | +| `review_shards.hard_cap` | 48 | Maximum accepted review shard count. | +| `commit_review.page_size_default` | 2 | Commits selected per commit-review page. | +| `commit_review.page_size_hard_cap` | 48 | Maximum commit-review page size. | +| `repair_live_runs.default` | 19 | Default live repair workflow run cap for manual dispatch/requeue/self-heal. | +| `repair_live_runs.hard_cap` | 48 | Absolute live repair run cap accepted by explicit CLI/env overrides with this config. | +| `repair_live_runs.automerge_default` | 19 | Live repair run cap for automerge comment-router dispatches. | +| `repair_live_runs.issue_implementation_default` | 19 | Live repair run cap for issue-to-PR implementation intake. | | `repair_live_runs.cluster_default` | 2 | Live repair run cap for imported gitcrawl cluster dispatches. | | `issue_implementation.dispatches_per_sweep_default` | 1 | Maximum implementation intake jobs queued from one review publish run. | Formula summary: -- normal review: 70% of `workers.max` +- normal review: the smaller of 70% of `workers.max` and the capacity left + after interactive and expansion reserves - normal active floor: 30% of `workers.max` - hot intake: 35% of `workers.max` - commit review page size: 5% of `workers.max` @@ -124,13 +126,13 @@ keeps capacity waiting and retry state out of GitHub Actions runners. Examples with the current config: -- Quiet system: manual normal review can request 22 shards; scheduled normal - review gets 12 after reserving 8 slots for exact/manual/urgent work and 12 +- Quiet system: manual normal review can request 28 shards; scheduled normal + review gets 28 after reserving 8 slots for exact/manual/urgent work and 12 slots for in-flight matrix expansion. - 4 active repair workers and 8 active background workers: normal review gets - 1 because `32 - 8 interactive reserve - 12 expansion reserve - 4 priority - - 8 background = 0`, and enabled background lanes keep one slow-progress worker. -- 24 active priority workers: commit review gets 1, so commit review yields but + 16 because `48 - 8 interactive reserve - 12 expansion reserve - 4 priority + - 8 background = 16`. +- 46 active priority workers: commit review gets 1, so commit review yields but does not fully stall. Use these commands to inspect the effective values from a checkout: @@ -143,9 +145,9 @@ pnpm run --silent workflow -- worker-limit commit_review --active-critical 88 ``` Change `workers.max` first when tuning review-side rate-limit pressure. For -example, setting `workers.max` to `40` automatically makes normal review `28`, -hot intake `14`, and commit review `2`. Existing repair lanes keep their -40% derived caps, while imported cluster repair remains separately bounded until +example, setting `workers.max` to `48` makes normal review `28`, hot intake +`16`, and commit review `2`. Existing repair lanes use their 40% derived caps, +while imported cluster repair remains separately bounded until `lanes.repair.cluster_max_live_runs` is raised. ## Runtime Overrides diff --git a/docs/live-dashboard.md b/docs/live-dashboard.md index 3112620852..e02eb9e309 100644 --- a/docs/live-dashboard.md +++ b/docs/live-dashboard.md @@ -130,8 +130,8 @@ The Worker fetches job details only for the bounded active-run set, limits that GitHub fanout to 12 concurrent requests, and caches each run's jobs for 60 seconds. It separately samples 20 recent completed worker runs with ten-way fanout and caches error/recovery telemetry for 120 seconds. This bounds -telemetry pressure without exceeding the 32-worker fleet budget. Worker details -paginate up to 300 jobs per workflow run so 22-shard runs remain fully visible, +telemetry pressure without exceeding the 48-worker fleet budget. Worker details +paginate up to 300 jobs per workflow run so 28-shard runs remain fully visible, then finish before optional pipeline CI and historical enrichment begin, so those secondary lookups do not compete with active worker telemetry. If GitHub job telemetry is unavailable, the API and UI retain the diff --git a/docs/repair/README.md b/docs/repair/README.md index 02b9917604..c49668f9c0 100644 --- a/docs/repair/README.md +++ b/docs/repair/README.md @@ -274,12 +274,12 @@ pnpm run repair:import-gitcrawl -- --from-gitcrawl --limit 40 --mode autonomous # Dispatch reviewed jobs. Dispatch derives its default live-worker cap from the # job's job_intent and config/automation-limits.json. Existing repair lanes -# keep the normal 40%-of-workers.max cap, currently 12; imported gitcrawl +# keep the normal 40%-of-workers.max cap, currently 19; imported gitcrawl # cluster jobs default to lanes.repair.cluster_max_live_runs, currently 2. # Use CLAWSWEEPER_MAX_LIVE_WORKERS/--max-live-workers for a one-lane override. # With --wait-for-capacity, dispatch can drain a larger file # list in capacity-sized waves instead of refusing the whole batch. -CLAWSWEEPER_MAX_LIVE_WORKERS=12 pnpm run repair:dispatch -- jobs/openclaw/inbox/ordinary-example.md \ +CLAWSWEEPER_MAX_LIVE_WORKERS=19 pnpm run repair:dispatch -- jobs/openclaw/inbox/ordinary-example.md \ --mode autonomous \ --runner blacksmith-4vcpu-ubuntu-2404 \ --execution-runner blacksmith-16vcpu-ubuntu-2404 diff --git a/docs/scheduler.md b/docs/scheduler.md index a935ebdde2..81cf73ea46 100644 --- a/docs/scheduler.md +++ b/docs/scheduler.md @@ -22,11 +22,11 @@ ClawSweeper has three issue/PR scheduler paths: The lanes share report storage and apply rules, but they intentionally do not share throughput. Event review and hot intake keep new maintainer-visible work -fast. Scheduled normal backfill keeps up to 12 concurrent Codex review shards -when quiet; manual backfill can use up to 22 concurrent Codex review shards. +fast. Scheduled normal backfill keeps up to 28 concurrent Codex review shards +when quiet; manual backfill can use up to 28 concurrent Codex review shards. Normal `openclaw/openclaw` review has an -active floor of 9 shards for scheduled runs and workflow-dispatch -continuations: due items win first, and if fewer than 9 items are due, the +active floor of 14 shards for scheduled runs and workflow-dispatch +continuations: due items win first, and if fewer than 14 items are due, the planner fills the floor with the stalest currently-reviewed eligible items so review capacity stays warm around the clock. @@ -220,19 +220,19 @@ Current defaults: - exact event review: 1 shard, 1 item - exact manual hot intake: 1 shard, 1 item -- broad hot intake: up to 11 shards when quiet, batch size 1, scans up to 10 +- broad hot intake: up to 16 shards when quiet, batch size 1, scans up to 10 GitHub pages -- scheduled normal backfill: up to 12 shards when quiet, batch size 3, scans up +- scheduled normal backfill: up to 28 shards when quiet, batch size 3, scans up to 250 GitHub pages after reserving interactive and expansion capacity -- normal active floor: 9 shards for `openclaw/openclaw` scheduled runs and +- normal active floor: 14 shards for `openclaw/openclaw` scheduled runs and workflow-dispatch continuations; stale current-review backfill is eligible after 6 hours -- manual normal backfill: defaults to 22 shards, batch size 3, scans up to 250 +- manual normal backfill: defaults to 28 shards, batch size 3, scans up to 250 GitHub pages unless overridden, and stops early once scanned due candidates fill planned capacity -The hard planner cap is 32 shards. The workflow clamps invalid or larger -`shard_count` inputs to 32. +The hard planner cap is 48 shards. The workflow clamps invalid or larger +`shard_count` inputs to 48. Broad background review also clamps manual `shard_count` input to the current lane allowance from `worker-limit`. Pending or planning background sweeps reserve @@ -244,7 +244,7 @@ Planning is also the runtime build point for matrix review. The plan job install with pinned Node 24 and `pnpm@10.33.2`, builds `dist/` once, and uploads that runtime artifact. Review shards download the built `dist/` and run `node dist/clawsweeper.js review` directly instead of running a per-shard pnpm -install and build. This keeps 11-22 shard waves from stampeding the npm +install and build. This keeps 16-28 shard waves from stampeding the npm registry or Corepack metadata endpoints. Each review shard also wraps the review command in a shell timeout derived from @@ -262,7 +262,7 @@ because they may rebase and push generated records. Normal backfill now runs every 5 minutes for `openclaw/openclaw`. Because its concurrency group allows only one running normal backfill per target repo, the effect is a continuous drain loop: when due backlog exists, the active run can -hold up to 12 Codex review shards with up to three items per shard, and the next +hold up to 28 Codex review shards with up to three items per shard, and the next scheduled tick is available as the backstop or pending continuation. Manual normal reviews keep the larger default batch size for targeted catch-up runs. @@ -280,10 +280,10 @@ live Codex count past the global budget. The active floor is not a separate lane and does not change close/apply safety. It only changes normal planning when due backlog is below the desired floor: -after selecting all due candidates, the planner fills up to 9 nonempty shards +after selecting all due candidates, the planner fills up to 14 nonempty shards with eligible items whose latest complete review is at least 6 hours old. Capacity status reports this as `floor: due backlog below active floor`. If the -central worker scheduler returns fewer than 9 allowed shards, the smaller +central worker scheduler returns fewer than 14 allowed shards, the smaller worker allowance wins. On saturated queues, normal planning stops scanning as soon as it has enough due @@ -446,7 +446,7 @@ or syncs the durable ClawSweeper review comment. Broad normal review publishes records first, then dispatches durable review comment sync into the separate apply/comment-sync lane. This includes scheduled runs and workflow-dispatch continuations, so slow GitHub comment writes do not -hold the normal review concurrency group or delay the next 12-shard backfill +hold the normal review concurrency group or delay the next 28-shard backfill wave. Exact issue/PR reviews and repository-dispatch item runs still sync their selected comments inline before finishing. diff --git a/docs/steerable-repair-automation.md b/docs/steerable-repair-automation.md index adca52ded5..2548cbc3ff 100644 --- a/docs/steerable-repair-automation.md +++ b/docs/steerable-repair-automation.md @@ -527,13 +527,13 @@ Current global and key lane limits: | Limit | Value | | --- | ---: | -| Global Codex worker budget | 32 | +| Global Codex worker budget | 48 | | Interactive reserve | 8 | | Expansion reserve | 12 | -| Existing repair, PR repair, and issue implementation default | 12 | +| Existing repair, PR repair, and issue implementation default | 19 | | Imported GitCrawl cluster repair | 2 | -| Quiet normal-review ceiling | 22 | -| Quiet hot-intake ceiling | 11 | +| Quiet normal-review ceiling | 28 | +| Quiet hot-intake ceiling | 16 | Important behavior: diff --git a/scripts/check-limits.ts b/scripts/check-limits.ts index 4326a89a79..c19696fa1c 100644 --- a/scripts/check-limits.ts +++ b/scripts/check-limits.ts @@ -74,7 +74,12 @@ const expectations: { file: string; label: string; pattern: RegExp }[] = [ { file: "dashboard/worker.ts", label: "dashboard worker budget fallback", - pattern: new RegExp(`numberFrom\\(env\\.WORKER_BUDGET, ${config.workers.max}\\)`), + pattern: /numberFrom\(env\.WORKER_BUDGET, DEFAULT_WORKER_BUDGET\)/, + }, + { + file: "dashboard/worker.ts", + label: "dashboard worker budget default", + pattern: new RegExp(`DEFAULT_WORKER_BUDGET = ${config.workers.max}\\b`), }, { file: "README.md", @@ -133,14 +138,14 @@ for (const [limitPath, value] of Object.entries(flattenLimits(limits))) { expectations.push({ file: "docs/limits.md", label: `${limitPath} documented current value`, - pattern: new RegExp(`\\| \`${escapeRegExp(limitPath)}\` \\| ${value} \\|`), + pattern: new RegExp(`\\|\\s*\`${escapeRegExp(limitPath)}\`\\s*\\|\\s*${value}\\s*\\|`), }); } for (const [limitPath, value] of Object.entries(flattenLimits(config))) { expectations.push({ file: "docs/limits.md", label: `${limitPath} documented worker config value`, - pattern: new RegExp(`\\| \`${escapeRegExp(limitPath)}\` \\| ${value} \\|`), + pattern: new RegExp(`\\|\\s*\`${escapeRegExp(limitPath)}\`\\s*\\|\\s*${value}\\s*\\|`), }); } @@ -183,7 +188,15 @@ function deriveAutomationLimits(workerConfig: WorkerConfig): AutomationLimits { default: Math.min(workerConfig.lanes.assist.max, max), }, review_shards: { - normal_default: percent(max, 70), + normal_default: Math.min( + percent(max, 70), + Math.max( + 1, + max - + workerConfig.workers.reserve_for_interactive - + workerConfig.workers.expansion_reserve, + ), + ), normal_active_floor: percent(max, 30), hot_intake_default: percent(max, 35), exact_item_default: 1, diff --git a/src/limits.ts b/src/limits.ts index 5951c54281..1f502c796a 100644 --- a/src/limits.ts +++ b/src/limits.ts @@ -74,7 +74,13 @@ export function deriveAutomationLimits(config: WorkerConfig): AutomationLimits { concurrent_max: Math.min(config.lanes.exact_review.max_concurrent, max), }, review_shards: { - normal_default: percent(max, 70), + normal_default: Math.min( + percent(max, 70), + Math.max( + 1, + max - config.workers.reserve_for_interactive - config.workers.expansion_reserve, + ), + ), normal_active_floor: percent(max, 30), hot_intake_default: percent(max, 35), exact_item_default: 1, diff --git a/src/repair/limits.ts b/src/repair/limits.ts index 2f7df1cfd3..c666f09f1f 100644 --- a/src/repair/limits.ts +++ b/src/repair/limits.ts @@ -84,7 +84,13 @@ export function deriveAutomationLimits(config: WorkerConfig): AutomationLimits { default: Math.min(config.lanes.assist.max, max), }, review_shards: { - normal_default: percent(max, 70), + normal_default: Math.min( + percent(max, 70), + Math.max( + 1, + max - config.workers.reserve_for_interactive - config.workers.expansion_reserve, + ), + ), normal_active_floor: percent(max, 30), hot_intake_default: percent(max, 35), exact_item_default: 1, diff --git a/test/dashboard-worker.test.ts b/test/dashboard-worker.test.ts index c6ea749cf9..56eb5ae177 100644 --- a/test/dashboard-worker.test.ts +++ b/test/dashboard-worker.test.ts @@ -14,10 +14,11 @@ import { triageRoutingGroupsForLabels, } from "../dashboard/triage-routing-groups.ts"; -test("exact-review queue defaults to 4 of the 32 global workers", () => { +test("exact-review queue defaults to 4 of the 48 global workers", () => { assert.equal(exactReviewQueueCapacity({}), 4); assert.equal(exactReviewQueueCapacity({ EXACT_REVIEW_QUEUE_MAX_CONCURRENT: "32" }), 32); - assert.equal(exactReviewQueueCapacity({ EXACT_REVIEW_QUEUE_MAX_CONCURRENT: "100" }), 32); + assert.equal(exactReviewQueueCapacity({ EXACT_REVIEW_QUEUE_MAX_CONCURRENT: "48" }), 48); + assert.equal(exactReviewQueueCapacity({ EXACT_REVIEW_QUEUE_MAX_CONCURRENT: "100" }), 48); }); test("triage routing groups classify impact labels without forcing one primary group", () => { @@ -1968,7 +1969,7 @@ test("dashboard counts active runs that are older than the latest unfiltered pag assert.equal(status.fleet.queued_workflow_runs, 1); assert.equal(status.fleet.support_workflow_runs, 3); assert.equal(status.fleet.support_queued_workflow_runs, 1); - assert.equal(status.fleet.worker_budget, 32); + assert.equal(status.fleet.worker_budget, 48); assert.deepEqual( status.pipeline.map((row: { id: number }) => row.id), [2, 4, 3], diff --git a/test/repair/live-worker-capacity.test.ts b/test/repair/live-worker-capacity.test.ts index 3c5434818a..8ecdd9547e 100644 --- a/test/repair/live-worker-capacity.test.ts +++ b/test/repair/live-worker-capacity.test.ts @@ -13,13 +13,13 @@ import { } from "../../dist/repair/live-worker-capacity.js"; test("live worker capacity refuses limits above the global Codex cap", () => { - assert.equal(MAX_LIVE_WORKERS, 32); - assert.equal(readMaxLiveWorkers(), 12); + assert.equal(MAX_LIVE_WORKERS, 48); + assert.equal(readMaxLiveWorkers(), 19); assert.equal(readMaxLiveWorkers({ "max-live-workers": "1" }), 1); - assert.equal(readMaxLiveWorkers({ "max-live-workers": "31" }), 31); + assert.equal(readMaxLiveWorkers({ "max-live-workers": "48" }), 48); assert.throws( - () => readMaxLiveWorkers({ "max-live-workers": "129" }), - /max-live-workers must be <= 32/, + () => readMaxLiveWorkers({ "max-live-workers": "49" }), + /max-live-workers must be <= 48/, ); });