Skip to content

refactor(runtime): extract rotation-proxy closure state (phase 2) - #548

Closed
ndycode wants to merge 1 commit into
claude/audit-15-rotation-proxy-carvefrom
claude/audit-28-rotation-proxy-phase2
Closed

refactor(runtime): extract rotation-proxy closure state (phase 2)#548
ndycode wants to merge 1 commit into
claude/audit-15-rotation-proxy-carvefrom
claude/audit-28-rotation-proxy-phase2

Conversation

@ndycode

@ndycode ndycode commented Jun 10, 2026

Copy link
Copy Markdown
Owner

Summary

Phase 2 of the runtime-rotation-proxy.ts decomposition — audit roadmap §4.1.3 (docs/audits/AUDIT_2026-06-10.md, PR #522): the closure-entangled state that phase 1 deliberately deferred moves into explicit state-object modules. The proxy shrinks 2,099 → 1,505 lines (2,498 → 1,505 across both phases). Zero behavior change.

Stacked on #532 (claude/audit-15-rotation-proxy-carve). Merge #532 first; this PR then shows only the phase-2 commit.

Extractions (all new modules; none imports runtime-rotation-proxy.ts back)

Module Lines Contents
lib/runtime/rotation-proxy-state.ts 116 RotationProxyState container (status object, session-affinity store, thread-goal fallbacks, rotation stickiness, active AccountManager, stale-reload dedupe fields) + createRotationProxyState + recoverStaleRuntimeState
lib/runtime/rotation-account-selection.ts 257 chooseAccount + chooseLinearScanFallback, verbatim
lib/runtime/rotation-token-refresh.ts 141 ensureFreshAccessToken, the refresh-commit dedupe WeakMap, applyMonotonicAuthCooldown, DEFAULT_AUTH_FAILURE_COOLDOWN_MS
lib/runtime/rotation-storage-meta.ts 206 StorageMeta, content-hash cache, readStorageMetaFromDisk, readPinnedAccountIndexFromDisk, resetPinCacheForTesting, maybeInvalidateAffinityFromDisk, verbatim

The request handler (handleRequest/handleRequestInner, containing the rotation loop) is lifted out of the startRuntimeRotationProxy closure into module-level functions taking the state object; every closure variable became a state field. git diff -w shows only state-field substitutions, import/re-export wiring, and the lifted function headers. All previously-exported symbols remain exported from lib/runtime-rotation-proxy.ts; non-facade cross-module exports are /** @internal */. The 3 call sites (lib/index.ts, scripts/codex.js, scripts/codex-app-router.js) and every test file are untouched.

Deliberately not moved: the HTTP plumbing (request-context builders, writeJson/writePoolExhausted, header/auth helpers, persistRuntimeActiveAccount, server lifecycle). The rotation loop depends on ~15 such helpers; moving them would relocate essentially the whole module rather than de-entangle closure state.

Validation

  • npm run typecheck; eslint on all 5 touched files --max-warnings=0
  • npx madge --circular: no cycle involves any rotation module (the 27 pre-existing storage/accounts cycles are unchanged)
  • Proxy suites (runtime-rotation-proxy, safe-equal, issue-474 ×4): 152 passed, 2 failed — both the known IPv6 ::1 environment failures
  • codex-app-router + codex-bin-wrapper: 101 passed / 6 skipped / 3 failed — the 3 known Windows-path environment failures
  • Failure parity verified via git stash push -u against base 4d5dd51: identical counts and identical failing test names on both sides
  • Independently re-verified: typecheck + runtime-rotation-proxy suite (76/78, same 2 env failures) + eslint

Risk / Rollback

Mechanical closure-state extraction (riskier than phase 1 by nature, hence the dedicated PR); revert the single phase-2 commit.

https://claude.ai/code/session_01XNtnkLbBiXZxfQQYLMpucB


Generated by Claude Code

note: greptile review for oc-chatgpt-multi-auth. cite files like lib/foo.ts:123. confirm regression tests + windows concurrency/token redaction coverage.

Greptile Summary

phase 2 of the runtime-rotation-proxy.ts decomposition: extracts closure-entangled state into four new modules (rotation-proxy-state, rotation-account-selection, rotation-storage-meta, rotation-token-refresh) and lifts handleRequest/handleRequestInner out of the startRuntimeRotationProxy closure into module-level functions that take an explicit RotationProxyState object. all closure variable accesses become state.field reads with no semantic change.

  • RotationProxyState container (rotation-proxy-state.ts): holds all mutable per-instance fields; recoverStaleRuntimeState correctly deduplicates concurrent stale-reload attempts via a promise ref and a 1 s wall-clock guard; close() retains the correct state.activeAccountManager reference semantics.
  • verbatim lifts (rotation-account-selection.ts, rotation-storage-meta.ts, rotation-token-refresh.ts): chooseAccount, readStorageMetaFromDisk (windows mtime-collision-safe, path-keyed cache), and ensureFreshAccessToken (WeakMap commit dedup) are moved unchanged; all previously-exported symbols are re-exported through runtime-rotation-proxy.ts.

Confidence Score: 4/5

mechanical closure extraction with no behavior change; re-export surface is intact and the routing-mutex concurrency contract is fully preserved across all four new modules.

all four new modules are verbatim lifts or direct closure-to-state-field substitutions; the stale-reload dedup, token-refresh WeakMap, and windows-safe mtime cache each retain exactly their original semantics. the only gap is that none of the four new modules have a dedicated unit test file — recoverStaleRuntimeState, ensureFreshAccessToken, and the commitRefreshedAuthOnce dedup path are covered only through the integration proxy suite, leaving individual state paths (e.g. the 1s reload dedup boundary, the commit-once collision) untested in isolation.

lib/runtime/rotation-proxy-state.ts and lib/runtime/rotation-token-refresh.ts — both carry observable stateful paths (reload dedup, refresh commit dedup) with no dedicated test file.

Important Files Changed

Filename Overview
lib/runtime-rotation-proxy.ts handleRequest and handleRequestInner lifted out of the startRuntimeRotationProxy closure into module-level functions taking RotationProxyState; all closure variable accesses converted to state.field reads; re-export surface preserves every previously-exported symbol; close() correctly reads state.activeAccountManager (same reference semantics as the original let variable).
lib/runtime/rotation-proxy-state.ts new module: extracts RotationProxyState container and recoverStaleRuntimeState; semantics are mechanically equivalent to the original closure; dedupe and promise-chain ordering are correct; no dedicated unit tests exist for this file.
lib/runtime/rotation-account-selection.ts new module: verbatim lift of chooseAccount + chooseLinearScanFallback; concurrency contract (routing mutex serialization, advanceActivePointer guard) is preserved; pre-existing indentation artifact in the affinity branch carried over unchanged.
lib/runtime/rotation-storage-meta.ts new module: verbatim lift of readStorageMetaFromDisk, content-hash cache, and affinity-invalidation helpers; STORAGE_META_CACHE remains module-level and path-keyed (preserves windows mtime-collision safety, vitest worker isolation); all four previously-exported symbols re-exported via runtime-rotation-proxy.ts.
lib/runtime/rotation-token-refresh.ts new module: lifts ensureFreshAccessToken, applyMonotonicAuthCooldown, and the runtimeRefreshCommitQueues WeakMap; all were module-level in the original (not closure-captured), so semantics are unchanged; no dedicated unit tests for the refresh dedup path.

Fix All in Codex

Prompt To Fix All With AI
Fix the following 1 code review issue. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 1
lib/runtime/rotation-proxy-state.ts:87-116
**no dedicated unit tests for the 4 new modules**

`recoverStaleRuntimeState`, `createRotationProxyState`, `ensureFreshAccessToken`, and the storage-meta cache functions are exercised only through the integration-level proxy suite — no unit tests in `test/` target any of the new files. the dedupe guard (`STALE_RUNTIME_RELOAD_DEDUPE_MS`), the `staleRuntimeReloadPromise` race-free single-reload path, and the `commitRefreshedAuthOnce` WeakMap dedup are all independently testable and would benefit from isolated vitest coverage. similarly, `rotation-storage-meta.ts` already has test helpers (`resetPinCacheForTesting`) that hint at this intent. per project convention, 80%+ coverage thresholds apply and new modules with observable state paths should carry their own test file.

Reviews (1): Last reviewed commit: "refactor(runtime): extract rotation-prox..." | Re-trigger Greptile

Phase 2 of the §4.1.3 rotation-proxy decomposition (follows the phase-1
carve, PR #532). The closure state inside startRuntimeRotationProxy is
now an explicit RotationProxyState container created once at startup
and passed to plain module-level functions; function bodies are
unchanged apart from closure-variable -> state-field references.

Module map:
- lib/runtime/rotation-proxy-state.ts (116 lines): RotationProxyState
  container (status, session-affinity store, thread-goal fallbacks,
  rotation stickiness, active AccountManager) plus the deduped
  recoverStaleRuntimeState reload.
- lib/runtime/rotation-account-selection.ts (257 lines): chooseAccount
  and the shared linear-scan fallback.
- lib/runtime/rotation-token-refresh.ts (141 lines):
  ensureFreshAccessToken, the per-manager refresh-commit dedupe
  WeakMap, and applyMonotonicAuthCooldown.
- lib/runtime/rotation-storage-meta.ts (206 lines): the content-hash
  storage-meta cache (readStorageMetaFromDisk and friends).

lib/runtime-rotation-proxy.ts: 2,099 -> 1,505 lines. Every previously
exported symbol is still exported from lib/runtime-rotation-proxy.ts
via re-exports, so lib/index.ts, scripts/codex.js,
scripts/codex-app-router.js, and all test imports are untouched. The
HTTP plumbing helpers (request parsing/forwarding, writeJson and
friends) deliberately stay in runtime-rotation-proxy.ts: moving them
would relocate the entire module rather than break up the closure
state.

https://claude.ai/code/session_01XNtnkLbBiXZxfQQYLMpucB
@chatgpt-codex-connector

Copy link
Copy Markdown

Codex usage limits have been reached for code reviews. Please check with the admins of this repo to increase the limits by adding credits.
Credits must be used to enable repository wide code reviews.

@coderabbitai

coderabbitai Bot commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

@ndycode, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 9 minutes and 26 seconds. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 4535bc04-8c9a-4e65-91f3-85466d7700b8

📥 Commits

Reviewing files that changed from the base of the PR and between 4d5dd51 and 3f3fdf2.

📒 Files selected for processing (5)
  • lib/runtime-rotation-proxy.ts
  • lib/runtime/rotation-account-selection.ts
  • lib/runtime/rotation-proxy-state.ts
  • lib/runtime/rotation-storage-meta.ts
  • lib/runtime/rotation-token-refresh.ts
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/audit-28-rotation-proxy-phase2
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch claude/audit-28-rotation-proxy-phase2

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 and usage tips.

ndycode pushed a commit that referenced this pull request Jun 10, 2026
The codex-manager and rotation-proxy decompositions are now fully
delivered (monolith 3,810 -> 690; proxy 2,498 -> 1,505). Remaining
deferred work narrows to the giant-suite mock-factory migrations.

https://claude.ai/code/session_01XNtnkLbBiXZxfQQYLMpucB
ndycode added a commit that referenced this pull request Jun 10, 2026
…hase2

refactor(runtime): extract rotation-proxy closure state (phase 2)
@ndycode ndycode closed this Jun 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants