Skip to content

fix(codex): carry canonical subagent limits across modes (#7125) - #7128

Merged
lidge-jun merged 5 commits into
devfrom
carry/subagent-limits-7125
Oct 15, 2026
Merged

lidge-jun merged 5 commits into
devfrom
carry/subagent-limits-7125

Conversation

@lidge-jun

@lidge-jun lidge-jun commented Oct 15, 2026 •

Copy link
Copy Markdown
Owner

Summary

  • Carry fix(codex): honor canonical subagent limits across modes #7125 by @luvs01 from 4bc46305ec63ed62b4f8db22b8f74a0b9460f612, preserving the original implementation and authorship. The fork disallows maintainer edits. Based on current origin/dev (7640a942b, including the fix(ci): remove the shared root causes of flaky Windows CI #7107 Windows fix).
  • Honor canonical [agents].max_concurrent_threads_per_session with legacy-alias compatibility, preserve child-count capacity across V1/base/hybrid/global-V2 modes, and prevent older settings responses from reverting a completed save. Keep the API's existing backend-specific units; the UI consistently edits child counts. Update the capacity contract and translated user guidance.
  • Fix the original failing test 3/4 regression at codex-config-write-lock.test.ts:530: an atomic V2-to-V1 toggle now writes the canonical key, while the old assertion still demanded max_threads. Assert the parsed agents table, including absence of the old alias. The original aggregate ci failure was downstream of that test failure. Correct the API field name in both carried architecture documents. Conflict warnings now identify the canonical agents key and its legacy alias in the CLI and every GUI locale, with focused regressions.

Co-authored-by: Epinephrine 27862058+luvs01@users.noreply.github.com

Verification

  • Reproduced before correction: write-lock suite 75 pass / 0 fail on dev, 74 pass / 1 fail on the carried contributor commit, matching the original failed run.
  • bun test tests/codex-integration/codex-agent-thread-limit.test.ts tests/codex-integration/codex-config-write-lock.test.ts tests/codex-integration/codex-v2-gate.test.ts tests/cli/cli-v2-runtime.test.ts tests/test-layout.test.ts tests/test-layout-tooling.test.ts: 360 pass, 0 fail.
  • From gui/, initial bun test tests/models: 166 pass, 0 fail across 19 files. After adding the conflict-warning regression, bun test tests/models-subagent-limit.test.tsx: 11 pass, 0 fail (the new warning test also failed against the previous copy). bun run lint, bun run lint:i18n, and bun run build: passed after the copy change. Final bun test tests/cli/cli-v2-runtime.test.ts: 112 pass, 0 fail. bun test tests/codex-integration/codex-missing-home.test.ts: 24 pass, 0 fail. Counts represent separate runs, not a summed whole-suite claim.
  • bun run typecheck, bun run structure:check, bun run privacy:scan, bun scripts/file-size-ratchet.ts, and git diff --check: passed.
  • From docs-site/, bun install --frozen-lockfile and bun run build: passed, 577 pages and 81,224 internal links checked.
  • Fresh browser smoke of the actual Models component with synthetic API fixtures: hybrid mode shows an editable child limit of 16; selecting 32 sends {maxConcurrentThreadsPerSession:32} and displays 32. This does not attest a running native host's reload behavior.
  • bun run test:changed (fresh, round 2, current head): 29,797 pass / 39 skip / 10 fail / 4 errors across 1,331 files. Every failure is attributed to a defect that reproduces on clean origin/dev (7640a942b) without this PR; none touches the limit code (no failing file references [agents] limits, transitionMultiAgentV2, or the Models limit UI):
    • Sibling-home timeout (1 fail + its unhandled errors): a secondary ensure parent preserves shared Grok, Codex and Claude agent bytes times out at 30 s with child exit 143. A serial bun test --isolate tests/cli/sibling-home-client-sync.test.ts gives the same 32 pass / 1 fail / 1 error on both branch and dev.
    • Live-audio readiness (3 fail): native open and non-readiness events cannot claim readiness (5 s timeouts). OCX_TEST_FULL_SUITE=1 bun test --isolate --parallel=4 over the five previously failing files gives an identical 322 pass / 4 fail / 4 errors on dev and branch, repeated twice per tree, with the same four failing tests. The clean-dev full bun run test also hits them.
    • Service state leak (6 fail: 4 service install state Codex SQLite home binding, 2 service diagnostics stale-path cases): these fail in under 1 ms because resolveServiceState() reads a foreign record from the legacy homedir()/.opencodex/service-state.json. Under the wrapper, Bun's homedir() stays at the run-wide sandbox shared by all workers, while each worker's preload moves process.env homes to a nested sandbox, so a service-state write anywhere in the run leaks to later readers. The leaked record's codexHome is a nested preload sandbox (…/opencodex-test-*/tmp/opencodex-test-*/.codex). Deterministic repro on clean dev with a seeded legacy file under a temp HOME: service-sqlite-home 2 pass / 3 fail and service.test.ts 208 pass / 3 fail (the two same service diagnostics cases plus rejects restore operations from a different CODEX_HOME); the unseeded control passes 5/5 and 211/211. Whether it fires depends on file ordering, so the clean-dev full run happened to pass these. This is a pre-existing harness isolation defect, out of scope for this carry.
    • Serially (OCX_TEST_NO_QUEUE=1 bun test --isolate <file>), cli-access-audio-live (36/36), responses-canonical-nonstream (41/41), service-sqlite-home (5/5), and service (211/211) pass on both branch and dev. Round 1's extra live-audio and buffered-response failures did not recur.
    • Clean-dev baseline: full bun run test on 7640a942b fails the same sibling-home and live-audio tests, plus a dev-only connected Desktop uses hub IDs across a cold restart failure.
  • Independent round-2 review: Codex 0.162.1's config schema accepts agents.max_concurrent_threads_per_session with max_threads as an alias (binary strings and the must be at least 1 validator), so the canonical key is the right source of truth in v1/base/hybrid modes, and full V2 keeps features.multi_agent_v2.max_concurrent_threads_per_session (total = children + 1). Legacy keys are rewritten only by an explicit limit save or a v2 transition. Config injection calls the transition only while the global v2 flag is on, a state codex-rs already refuses to boot with any [agents] limit present, so startup never silently renames a user's max_threads. Conflicting alias values refuse a write unless an explicit limit resolves them. The GUI converts units only when the global flag is on, and the stale-GET guard covers both read and write generations. Tests touching these paths use createTempHome/temp CODEX_HOMEs and restore env; no real user config is touched.
  • Linux/macOS/Windows: manual lane=all dispatch and PR CI on head c0a798c1ba8a1c050262ea99ae542aaea92a6340 are still queued as of 2026-10-15 09:30 UTC. Only the changes/select windows runner jobs have run, behind a repository-wide hosted-runner backlog of 100+ queued runs with one job in progress. No test job has produced a result for this head, so the PR stays draft until hosted CI completes. No changes to CI policy, production locks, ACLs, provider configuration, or user homes.

Hybrid mode exposes the child-count limit of 16 (synthetic API fixture)

Screenshot is stored only on the separate pr-assets branch and pinned by commit SHA.

Checklist

  • Scope stays focused and avoids unrelated cleanup.
  • Docs or release notes were updated when needed.
  • Security-sensitive changes were reviewed for secrets, auth, and unsafe defaults. No auth, credential, ACL, release, workflow, or dependency changes.
  • Required local and hosted validation completed on the current head.
  • Independent maintainer review completed; this carry remains draft while validation is pending.

luvs01 and others added 2 commits October 15, 2026 16:18
Read and write the canonical Codex thread limit consistently with supported aliases. Keep the subagent selector available across modes, normalize child-count units, and reject stale settings responses. Cover canonical settings, mode behavior, and response ordering with focused regressions and update the capacity documentation.
Carry #7125 from 4bc4630. The write-lock regression must assert the canonical agents table after V2-to-V1 conversion, including absence of a legacy alias. Correct the API field name in the capacity contract.

Co-authored-by: Epinephrine <27862058+luvs01@users.noreply.github.com>
@coderabbitai

coderabbitai Bot commented Oct 15, 2026

Copy link
Copy Markdown
Contributor

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

Copy link
Copy Markdown
Contributor

✅ Deterministic PR hygiene checks passed.

@github-actions github-actions Bot added the bug Something isn't working label Oct 15, 2026
@lidge-jun

Copy link
Copy Markdown
Owner Author

Maintainer integration into dev (MAINTAINERS.md dev maintainer-integration policy; batch integration authorized by @lidge-jun on 2026-10-15).

  • Head: 7208c11cddcc2585e25d2be7a21e688026c3a63f (tree 57babf15700cebb3c1d682b5c960d32a3e12295f) = this branch merged with origin/dev 6fa42285f5.
  • Exact-head evidence: GitHub-hosted Actions for this account have not been assigning runners since 2026-10-15 13:30 UTC, so by owner decision the evidence is a full bun run test (Bun 1.4.3 test runner, root and GUI dependencies installed, GUI built) of this exact tree on a maintainer host (Linux x86_64): exit 1, 7 min, 31 failing test(s), each also failing in the same host's baseline run of dev 60bf4c7 (environment-only): Codex shim install readiness > a refused install exits unsuccessfully and preserves its re, Codex shim install readiness > keeps install advisory when the Codex config cannot be read, Codex shim install readiness > the install command surfaces readiness warnings without lea, GUI pairing client > sends one bodyless origin-bound capability and redacts rejected bodie, Node launcher PATH fallback activation > broken bundle reaches validated PATH Bun, Node launcher PATH fallback activation > inspection bundle reaches validated PATH Bun, Node launcher PATH fallback activation > missing bundle reaches validated PATH Bun, a secondary ensure parent preserves shared Grok, Codex and Claude agent bytes, ….
  • Local gates on the same tree: bun run typecheck, file-size ratchet, test-layout and structure:check.
  • Hosted CI checks for this head may still be queued; they are not claimed as evidence.

@lidge-jun
lidge-jun marked this pull request as ready for review October 15, 2026 18:05
@lidge-jun
lidge-jun requested a review from Ingwannu as a code owner October 15, 2026 18:05
@lidge-jun
lidge-jun merged commit 359d31b into dev Oct 15, 2026
8 of 9 checks passed
@lidge-jun
lidge-jun deleted the carry/subagent-limits-7125 branch October 15, 2026 18:06
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 15, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-15T18:10:07.024898Z 7208c11 Draft marked ready
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 7208c11cdd

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +200 to +201
export function threadLimitToChildCount(limit: number, v2Enabled: boolean): number {
return v2Enabled ? Math.max(1, limit - 1) : limit;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Display zero children for a root-only V2 limit

When global V2 stores maxConcurrentThreadsPerSession = 1, that value permits only the root thread and therefore represents zero children, but this clamp reports one child. The Models selector and folded summary consequently overstate the available capacity, and selecting the displayed value is treated as a no-op rather than changing storage to a total of 2. Preserve the actual zero-child value for display and handle its read-only or editable representation explicitly.

AGENTS.md reference: gui/AGENTS.md:L7-L10

Useful? React with 👍 / 👎.

Comment thread src/codex/features.ts
Comment on lines +1581 to +1582
if (options.threadLimit !== undefined && (!Number.isSafeInteger(options.threadLimit) || options.threadLimit < 1)) {
return { ok: false, error: "thread limit must be a safe integer >= 1" };

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Validate unsafe thread limits before invoking the transition

Now that this transition rejects non-safe integers, the management route still accepts values such as 9007199254740992 with Number.isInteger, and the GUI custom-limit path does the same before issuing its PUT. Those inputs therefore pass public validation and are reported as a 502 transition failure instead of the documented validation error; in V2, even a safe child count can become unsafe after adding the root slot. Validate the final backend-unit value with Number.isSafeInteger in both request entry points and return the normal 400/inline error.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants