🤖 refactor: convert codex/governor/copilot OAuth services to Effect and adopt handlerGen for OAuth procedures - #4034
Conversation
… move OAuth router procedures to handlerGen
|
@codex review |
This comment has been minimized.
This comment has been minimized.
|
@codex security review |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 83338825a7
ℹ️ 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".
… JSON payloads (Codex review)
|
@codex review |
|
@codex security review |
This comment has been minimized.
This comment has been minimized.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 4f78d9a585
ℹ️ 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".
|
@codex review |
|
@codex security review |
This comment has been minimized.
This comment has been minimized.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 968d21d16a
ℹ️ 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".
|
@codex review |
|
@codex security review |
|
Codex Review: Didn't find any major issues. Can't wait for the next one! Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
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". |
Summary
Wave 2 / Phase 6a of the progressive Effect migration: converts the three sibling OAuth services —
codexOauthService,muxGovernorOauthService, andcopilotOauthService— to Effect-native internals following themuxGatewayOauthServicetemplate from #4033, and moves all 15 OAuth router procedures (gateway, copilot, governor, codex) tohandlerGen.Background
#4033 made
OAuthFlowManagerEffect-native (per-flowScope) and exposed never-failing wire-shaped*Effectsurfaces (waitForEffect/cancelEffect/finishEffect/shutdownAllEffect), with the gateway'sdesktopCallbackPipelineas the conversion template. Phase 5 recommended splitting Phase 6 into two PRs: this is PR A (the mechanical sibling batch).coderOauthServiceis deliberately untouched (Phase 6b, see notes below).Implementation
House pattern throughout:
Effect.geninternals, one reason-carrying tagged error per service (CodexOauthError,MuxGovernorOAuthError,CopilotOauthError), thinEffect.runPromisePromise facades so every existing test passes unchanged.toWireResult(oauthUtils.ts): folds a{ reason: string }-typed failure channel into the wireResult<_, string>. Generic over the error type, so a tag a caller must branch on first (e.g.MuxGatewaySessionExpiredError) is rejected at compile time. The gateway's local copy is replaced with this shared helper.startDesktopFlowEffectisEffect.uninterruptible(like the gateway's — a client abort between loopback acquisition anddesktopFlows.registerwould leak the server). The forkeddesktopCallbackPipelinemirrors the gateway shape; service pipelines yield the manager's*Effectsurfaces directly (norunPromiseround-trips inside Effect code), and registration-timeout callbacks useEffect.runFork(manager.finishEffect(...)).startDeviceFlowEffectis uninterruptible (run-to-completion registration of the flow record + expiry timeout after the device-code allocation). Polling loops become forked fibers, but cancellation stays on the existing seams (AbortControllerfor codex,flow.cancelledfor copilot) — no fiber-interruption redesign. Codex's pre-Effect polling crash handler is mirrored withEffect.catchDefectat the fork site; copilot's transient-retrytry/catchbecomes an error-channel fold per poll iteration. ThepollingStartedguard + fork sit inside one sync step so an interrupt cannot mark polling started without launching it.waitForDeviceFlowEffectuses the manager-styleEffect.timeout+ fold instead of a hand-rolledsetTimeoutrace (same observable behavior: timer cleared when the deferred wins, shared deferred untouched on timeout).getValidAuthEffect: the refresh mutex is held viaEffect.acquireUseRelease(release guaranteed on success/failure/interruption — the Effect equivalent of the pre-Effectawait usinglock).handlerGen— gateway waitFor/cancel (2), copilot (3), governor (3), codex (7 incl.disconnect). Mutations that must not be stranded by client aborts are uninterruptible in the services; waits stay interruptible.Deliberate small behavior deltas (defect paths only): rejections from
setConfigValue/refreshNowfacades inside pipelines stay defects (logged by the fiber runtime) rather than being folded into error strings, matching the precedent set by the gateway conversion; the pre-Effect equivalents were unhandled rejections insidevoid (async () => …)()IIFEs.Notes for Phase 6b (
coderOauthService)desktopFlows.*call sites, including commit-path liveness checks viahas(flowId)— the finish/persist sequencing there is a correctness contract (a cancelled flow must not commit a replacement login), so it needs isolated review rather than mechanical conversion.finishis invoked after multi-await persist sections; converting those needs the same "sync bookkeeping now, async release in background" split thatbeginFinishprovides, with attention to which awaits sit between the liveness check and the commit.getValidAuththere has an issuer-binding check and its own cache; the codexacquireUseReleasemutex pattern from this PR should transfer directly.Validation
oauthFlowManager(20); plusrouter.test.tsand consumersproviderModelFactory.test.ts/server.test.ts/mcpOauthService.test.ts(205 tests). No test files modified.make static-checkgreen locally.Risks
Medium-touch refactor of login flows. The wire contracts, error strings, and cancellation semantics are preserved 1:1 (each conversion mirrors the original control flow, verified against the unchanged test suites). The main residual risk is interruption semantics under client aborts, which previously ran handlers to completion: flow-starting mutations and
disconnectare explicitly uninterruptible to preserve that, and waits are interruption-safe by construction of the shared deferred.Generated with
xum• Model:anthropic:claude-fable-5• Thinking:xhigh