Skip to content

Review only: HOUSE-79 upstream v8.0.44, part 3 of 13: codex executor - #16

Closed
ericlitman wants to merge 1 commit into
review/house79/base-03from
review/house79/chunk-03
Closed

ericlitman wants to merge 1 commit into
review/house79/base-03from
review/house79/chunk-03

Conversation

@ericlitman

@ericlitman ericlitman commented Oct 27, 2026 •

Copy link
Copy Markdown
Contributor

Review only. Do not merge. This PR is one part of the review of #13, the merge of upstream v8.0.44 into the fork. That PR's diff (966 files) is too large for one review round.

  • This part covers: codex executor.
  • The head tree is identical to Merge upstream v8.0.44 into the fork (HOUSE-79) #13 head tree (c88d701f7bc0894cde517ca7f931f5c05749cd74). The base is that tree with only this part's files restored to main (c265779f), so the diff is this part's files alone and the surrounding code is the real final code.
  • The 13 parts together cover every production file the sync changes (410 paths). Tests, golden data, generated model catalogs, images, docs and go.sum are in no part's diff.
  • The code is upstream's, except where our fork's soonest-reset selector, quota observations, quota reserves, usage reads and Terra injection touch it. Review it as code we are about to deploy to the proxy every one of our agents uses: report defects that would affect our deployment.

Linear: HOUSE-79

🤖 Generated with Claude Code


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need.

@mergify

mergify Bot commented Oct 27, 2026 •

Copy link
Copy Markdown
Contributor

This pull request does not currently match the merge queue conditions, so it cannot be queued from here. The box comes back if it matches again.

@unfret

unfret Bot commented Oct 27, 2026 •

Copy link
Copy Markdown

🛑 7 blocking findings

🟡 Medium · Use the finalized payload for image-tool usage attribution

🟡 Medium · Synchronize plan attributes when adopting disk credentials

🟡 Medium · Derive routing hints from the finalized model

🟡 Medium · Parse responses according to the finalized stream mode

🟡 Medium · Restrict TLS timeouts to credential acquisition

🟡 Medium · Select the tokenizer using the finalized model

🟡 Medium · Recognize explicit-port Alpha Search URLs

Walkthrough

This review-only slice of the upstream v8.0.44 sync brings the new Codex executor code into the fork. It adds Sign-in-with-ChatGPT (SIWC) credentials with a separate token, base URL, headers and body rules, and a file-locked, disk-aware credential refresh. It also adds opt-in zstd request compression with a plain-body retry, a multi-line SSE scanner, and moves user payload rules to a final barrier applied just before sending. The shared helpers gain response decoding, a TLS handshake timeout, websocket interrupt and steer handling, and new usage metadata. Several findings concern places that still read the payload or model from before payload rules run, plus credential and URL edge cases.

Area What changes Review notes
Codex credentials and refresh Adds SIWC token selection and a refresh path that locks the credential file, adopts tokens another process rotated on disk, refreshes outer and SIWC tokens one after the other, and writes a merged patch back to disk. Alpha Search requests still use the original OAuth token. Synchronize plan attributes when adopting disk credentials
Recognize explicit-port Alpha Search URLs
Payload finalization Replaces the inline payload-config step with a finalizer that runs in cacheHelper, before websocket framing, and in the token, image and media paths. Routing hints, the tokenizer, stream parsing and image usage attribution still read values from before that step. Derive routing hints from the finalized model
Select the tokenizer using the finalized model
Parse responses according to the finalized stream mode
Use the finalized payload for image-tool usage attribution
Transport Adds zstd request bodies with Content-Encoding alignment and a single plain-body retry on 400/415, and decodes compressed upstream responses. Makes websocket write compression configurable, sends the disconnect notification only after the error reaches the caller, and wraps uTLS clients with an opt-in TLS handshake timeout. Restrict TLS timeouts to credential acquisition
Streaming and websockets Adds an SSE scanner that joins JSON event data split across several data lines and counts every raw line against the bootstrap buffering budget. Adds per-turn websocket authorization, finalized response.steer frames, response.interrupt forwarding, and terminal-response tracking per connection.
Since the last review
  • New: Use the finalized payload for image-tool usage attribution
  • New: Synchronize plan attributes when adopting disk credentials
  • New: Derive routing hints from the finalized model
  • New: Parse responses according to the finalized stream mode
  • New: Restrict TLS timeouts to credential acquisition
  • New: Select the tokenizer using the finalized model
  • New: Recognize explicit-port Alpha Search URLs
Repair prompt

Read the Unfret check run for mobilyze-llc/CLIProxyAPI#16 at head f6766edcad7c8f8a0ebb50979095ef458ef16d50 (run panel:f6766edcad7c8f8a0ebb50979095ef458ef16d50:mV4E99wOeyE:qXHb0xTKahc, check). Use the check's App id and GET /repos/mobilyze-llc/CLIProxyAPI/check-runs/122312078671; its output.text contains the structured result. Compare it with the current code and head, verify that each listed mandatory finding still applies, repair only those that do, honor the repository constraints, and validate the changes. Leave advisories and accepted risks alone. A manually resolved thread is not a waiver.

Details
Lane / stage Model Effort Outcome Duration
broad-gpt-5.6-sol-xhigh / review openai/gpt-5.6-sol → gpt-5.6-sol · primary xhigh succeeded 11 min 4 s
broad-opus-5.5-max / review Not recorded Not recorded failed Not recorded
focal-gpt-5.6-sol-xhigh copy / review openai/gpt-6.1-sol → gpt-6.1-sol · primary xhigh succeeded 16 min 28 s
focal-gpt-5.6-sol-xhigh copy 2 / review openai/gpt-6.1-sol → gpt-6.1-sol · primary xhigh succeeded 15 min 13 s
judge / judge openai/gpt-6-astra → gpt-6-astra · primary high succeeded 1 min 59 s

First review of this pull request.
3 reviewers finished.
Commit f6766ed.
Check run.
Run: GET /unfret/run/panel:f6766edcad7c8f8a0ebb50979095ef458ef16d50:mV4E99wOeyE:qXHb0xTKahc.

@unfret review · @unfret status · @unfret help

@unfret unfret 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.

🛑 7 blocking findings
🟡 Medium · Use the finalized payload for image-tool usage attribution
🟡 Medium · Synchronize plan attributes when adopting disk credentials
🟡 Medium · Derive routing hints from the finalized model
🟡 Medium · Parse responses according to the finalized stream mode
🟡 Medium · Restrict TLS timeouts to credential acquisition
🟡 Medium · Select the tokenizer using the finalized model
🟡 Medium · Recognize explicit-port Alpha Search URLs
Check

Comment on lines +93 to +97
httpReq, upstreamBody, err := e.cacheHelper(ctx, from, url, req, body, auth, opts.Headers)
if err != nil {
return resp, err
}
applyCodexHeaders(httpReq, auth, apiKey, true, e.cfg, opts.Headers)
applyCodexRoutingHint(ctx, httpReq.Header, auth, baseModel, upstreamBody, opts.Headers)
applyModelHeaderOverrides(httpReq.Header, baseModel)
reporter.SetTranslatedReasoningEffort(upstreamBody, to.String())

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 Medium · Use the finalized payload for image-tool usage attribution

Payload rules now run inside cacheHelper, but the finalized upstreamBody never replaces body. For a request declaring image_generation with model gpt-image-2 and an override setting tools.0.model to gpt-image-1.5, upstream receives gpt-image-1.5 while publishCodexImageToolUsage reads the old body and attributes its tokens to gpt-image-2. This reproduces in both Execute here and ExecuteStream at codex_executor_stream.go:100. Also reported for this defect: - Use the finalized tool model for image usage (internal/runtime/executor/codex_executor_execute.go:93): After cacheHelper applies payload rules, only upstreamBody contains the configured payload; body remains unconfigured. With an override changing tools.0.model from gpt-image-2 to gpt-image-1.5, the request correctly sends gpt-image-1.5, but publishCodexImageToolUsage still receives body and records the image tokens against gpt-image-2. This reproduces in both Execute and ExecuteStream, including its buffered and unbuffered completion branches, producing incorrect model-specific usage accounting.

Also affects:

Comment on lines +220 to +222
auth.Metadata[key] = val
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 Medium · Synchronize plan attributes when adopting disk credentials

When another process has rotated the credential file and the new token is no longer due, this branch updates Metadata["plan_type"] but leaves Attributes["plan_type"] unchanged. With an in-memory plus credential and refreshed disk credentials marked free, Refresh succeeds while isCodexFreePlanAuth still returns false, causing subsequent requests to inject image_generation and select the wrong plan capabilities. Disk adoption needs the same plan-attribute synchronization as a successful OAuth refresh. Also reported for this defect: - Synchronize plan attributes after disk rotation (internal/runtime/executor/codex_executor_auth.go:221): Disk reconciliation copies a newly refreshed plan_type only into Metadata, leaving Attributes["plan_type"] stale. For example, after another process persists a plus-to-free plan change, this process can still make isCodexFreePlanAuth return false and inject image-generation tools that the free credential cannot use, causing the next request to be rejected.

Also affects:

reporter.SetTranslatedReasoningEffort(upstreamBody, to.String())
prepareHeaders := func(request *http.Request) {
applyCodexHeaders(request, auth, apiKey, true, e.cfg, opts.Headers)
applyCodexRoutingHint(ctx, request.Header, auth, baseModel, upstreamBody, opts.Headers)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 Medium · Derive routing hints from the finalized model

Payload model overrides now survive finalization, but the routing hint still uses the original baseModel. For example, overriding a gpt-5.4 request to gpt-5.5 sends body.model=gpt-5.5 alongside X-Codex-Routing-Hint: model=gpt-5.4, so the generated routing metadata names the wrong model. The same mismatch affects executeCompact, ExecuteStream, CodexWebsocketsExecutor.Execute, and prepareCodexWebsocketStream. Derive the model from the final payload while retaining explicit operator-header precedence.

}
rawJSON = helps.SanitizeCodexInputItemIDs(rawJSON)
httpReq, err := http.NewRequestWithContext(ctx, http.MethodPost, url, bytes.NewReader(rawJSON))
rawJSON = helps.FinalizePayload(ctx, rawJSON)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 Medium · Parse responses according to the finalized stream mode

Payload rules now run after the built-in stream:true assignment. If a valid payload rule sets stream:false, Execute receives a normal JSON Responses object but still scans exclusively for data: SSE events and returns an incomplete-stream error despite the successful upstream response; the streaming path likewise cannot handle the finalized non-stream mode.

if timeout <= 0 {
return ctx, func() {}
}
return context.WithTimeout(ctx, timeout)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 Medium · Restrict TLS timeouts to credential acquisition

AGENTS.md permits timeouts only during credential acquisition. This helper is invoked by both inference uTLS transports after TCP dialing and proxy CONNECT, and NewUtlsHTTPClient activates it for ordinary Claude/Codex inference whenever TLSHandshakeTimeoutSeconds is positive. A slow handshake is therefore canceled with DeadlineExceeded outside credential acquisition, contrary to the mandate; none of the listed timeout exceptions covers this path. Also reported for this defect: - Keep inference timeouts within the repository mandate (internal/runtime/executor/helps/utls_handshake_timeout.go:74): AGENTS.md permits timeouts only during credential acquisition, apart from its named exceptions. This timeout is used by both inference uTLS paths in utls_client.go after TCP dialing and proxy CONNECT, not during credential acquisition. With requests.tls-handshake-timeout-seconds enabled, an ordinary Claude or Codex inference attempt is terminated when this timer expires even while its caller context remains active. Cancelling the timer after a successful handshake does not satisfy the credential-acquisition-only rule.

body = helps.SetBoolIfDifferent(body, "stream", false)
body = normalizeCodexInstructions(body, helps.IsNativeCodexRequest(req.Payload, opts))

body = helps.NewPayloadFinalizer(e.cfg, e.Identifier(), baseModel, to.String(), "", originalTranslatedForPayload, req, opts)(body)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 Medium · Select the tokenizer using the finalized model

The new finalizer can change body.model, but the following tokenizer selection still uses the original baseModel. A gpt-5.4 request with instructions "こんにちは世界" and a payload override to gpt-3.5-turbo returns 2 input tokens, whereas the configured model's tokenizer returns 4 for the same final content. The token-count endpoint therefore reports a count for a different model than the payload used for generation.

apiKey, _ := codexCredsForRequest(req.Context(), auth, req.Header)
if codexUseSIWCForRequest(req.Context(), auth, req.Header) && req.URL != nil && req.URL.Scheme == "https" &&
req.URL.Host == "chatgpt.com" && req.URL.Path == "/backend-api/codex/alpha/search" {
// ChatGPT Alpha Search requires the original OAuth partition, not SIWC.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 Medium · Recognize explicit-port Alpha Search URLs

With SIWC enabled, an Alpha Search request to https://chatgpt.com:443/backend-api/codex/alpha/search misses this branch because URL.Host includes the port; host casing can fail similarly. The request consequently sends the SIWC token instead of the required original OAuth token and receives an authorization error.

@ericlitman

Copy link
Copy Markdown
Contributor Author

Closing: the review scope changed. Eric (2026-10-27): "i don't want to fix anything that's an issue in upstream - our only goal here is to validate our changes". Upstream code is out of scope. Our fork's own changes on v8.0.44 get one review PR instead. Findings from this part are recorded in the HOUSE-79 adjudication record. None was a defect in our code.

@ericlitman ericlitman closed this Oct 27, 2026
@ericlitman
ericlitman deleted the review/house79/chunk-03 branch October 27, 2026 19:16
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.

1 participant