Repository navigation
Third-party reasoning item IDs poison Official continuation after a model switch #302
Description
Problem
A Codex Desktop task becomes impossible to continue on an Official model after a third-party Native Responses turn emits a reasoning output item.
Observed on CodexHub 0.1.7 with Codex Desktop 26.727.6591.0:
- Continue an existing task with Ollama Cloud
deepseek-v4-flash:0731. - The external Responses stream emits a reasoning item with a provider-local ID such as
rs_<redacted>and no portable Official encrypted payload. - Switch the same task to Official
gpt-5.6-lunaand continue. - Every attempt fails with:
Item with id 'rs_<redacted>' not found. Items are not persisted when `store` is set to false. Try again with `store` set to true, or remove this item from your input.
The failure is not Luna availability: the same persisted item produced the same 404 on Luna, Terra, and Sol. Each turn made one initial request plus five reconnect attempts with the same request body before surfacing the error.
The preceding DeepSeek activity was also checked separately. It contained 21 tool calls, 21 unique call IDs, 21 unique argument payloads, and exactly one output per call. It was not a duplicated tool-call replay. The generic identical-looking command cards are the separate, already-tracked Task activity problem in #138.
Deterministic RED
A minimal request-shaping probe against both the installed runtime and the current checkout currently forwards the foreign ID:
payload = {
"model": "gpt-5.6-luna",
"store": False,
"stream": True,
"input": [
{
"type": "reasoning",
"id": "rs_external_not_on_openai",
"summary": [],
"content": None,
"encrypted_content": None,
},
{"type": "message", "role": "user", "content": "continue"},
],
}
out = compatible_request_body(
json.dumps(payload).encode(),
choose_upstream("gpt-5.6-luna"),
behavior_profile=BEHAVIOR_OFFICIAL_CODEX_APP_HTTP_PASSTHROUGH,
)Observed result:
{"model":"gpt-5.6-luna","store":false,"forwarded_reasoning_ids":["rs_external_not_on_openai"]}The red assertion is: no third-party/provider-local reasoning item ID reaches an Official store=false request.
Root cause
The failure chain is deterministic:
- The third-party response compatibility path hides raw reasoning text / non-Official encrypted content but preserves the upstream reasoning item and its
rs_*ID. - Codex persists that output item in task history.
- While the task remains on a third-party route,
_rewrite_internal_input_items()drops/rephrases internal reasoning history, so the external turns continue successfully. - After switching to Official,
BEHAVIOR_OFFICIAL_CODEX_APP_HTTP_PASSTHROUGHcallsofficial_passthrough_request_body(). That path rewrites the model, service tier, unsupported compaction items, andstore=false, but does not sanitize provider-local reasoning items. _sanitize_official_reasoning_items()is bypassed by strict Official passthrough. Even on the non-passthrough Official path it only removes non-Officialencrypted_content; it preserves the foreignidand reasoning item.- The Official backend interprets the foreign ID as a server-held item reference, cannot resolve it under
store=false, and returns 404.
Relevant boundaries:
src-python/codex_proxy.py::compatible_sse_line/_hide_reasoning_textsrc-python/codex_proxy.py::official_passthrough_request_bodysrc-python/codex_proxy.py::_sanitize_official_reasoning_items- Existing routing coverage around
test_official_body_removes_plaintext_reasoning_encrypted_content
Related reports
- Exact cross-provider failure class in CC Switch: [Bug] Synthetic Codex reasoning IDs fail after switching to native Responses farion1231/cc-switch#5825
- Adjacent Codex stateless item-ID regression: Regression after #34645: proxied Azure Responses provider sends item IDs with store=false and fails with "Item with id ... not found" openai/codex#35739
- CodexHub Preserve OpenCode tool-result history on third-party transparent Responses routes #193 concerns standard tool-call/result history on transparent third-party routes; it does not sanitize third-party reasoning IDs on the Official path.
- CodexHub Restore command output, edit diffs, and progress text in Task activity #138 owns generic/missing Task command activity rendering; it is not the 404 root cause.
No existing open or closed CodexHub Issue describes this third-party-to-Official rs_* history contamination.
Outcome
Make Responses history provider-portable across model switches. A provider-local or synthetic reasoning item must never be serialized to a different Official store=false route as a resolvable server-side reference.
For reasoning without proven portable Official encrypted state, fail closed by removing the foreign item from the Official request (or by another explicitly proven portable representation). Do not globally remove legitimate Official stateless encrypted reasoning or standard tool-call/result identity.
Acceptance criteria
- A deterministic regression reproduces the current red shape: third-party
reasoning.id=rs_*, no valid Official encrypted content, then Official strict passthrough withstore=false. - The Official upstream request contains no provider-local/synthetic reasoning item ID and does not trigger an item lookup.
- Empty third-party reasoning history is dropped safely; any non-empty summary/content policy is explicit, privacy-safe, and accepted by the Official endpoint.
- Genuine Official reasoning history with valid self-contained Official encrypted content remains usable across Official turns.
- Standard
function_call/function_call_output, custom tools, call IDs, ordering, compaction handling, and Official passthrough behavior outside this provenance boundary remain unchanged. - A real same-task Desktop gate completes one third-party tool turn, switches to Official Luna, and completes exactly once with zero item-not-found response, fallback, or reconnect storm.
- Sanitized diagnostics may record route transition, item classification, and count, but never raw IDs, prompts, reasoning, tool arguments, task identifiers, credentials, or paths.
Expected hotset
src-python/codex_proxy.pytests/test_routing.py- Existing real-client E2E harness/fixture only as needed for the bounded model-switch gate
Verification
python -m pytest -q tests/test_routing.py -k "reasoning and (official or switch or passthrough)"
python -m pytest -q --ignore=tests/test_real_client_e2e.py
python tests/fixtures/real_client_e2e/run-with-windows-watchdog.py --timeout-seconds 3600 -- python -m pytest -q tests/test_real_client_e2e.py
python scripts/report_quality_gates.py
git diff --checkreport_quality_gates.py is report-only.
Execution-Contract: v2
Verification-Class: strict
Manual-Evidence: one isolated same-task third-party Native Responses -> Official Luna switch with a preceding tool turn, exactly one successful Official completion, and zero item-not-found/reconnect
Architecture-Decision: unresolved — choose the narrow provider-provenance/portable-reasoning policy before implementation
Review-Owner: orchestrator
Activity
NOirBRight commentedon Aug 1, 2026
Orchestrator decision-complete implementation contract
Architecture decision is resolved for this Beta1 stop-the-bleeding fix:
inputhistory when the request isstore=false.type=reasoningitem, keep the entire item only when it has a valid self-contained Official encrypted payload (encrypted_contentwith the existing Official prefix/validation). Remove the entire item for provider-local, synthetic, plaintext-only, missing, or invalid encrypted reasoning. Do not rewrite it into a message and do not strip only its ID.message,function_call,function_call_output, custom-tool call IDs/results, ordering, compaction handling, or other strict passthrough fields.Claimed paths/resources:
src-python/codex_proxy.py: Official strict request-body boundary and bounded diagnostic classification.tests/test_routing.py: deterministic foreignrs_external_not_on_openaiRED-to-GREEN regression plus valid Official encrypted reasoning and preservation tests.Done when:
store=false.CI / gate, and exact-SHA strict review pass.item not found, fallback, or reconnect storm.Execution-Contract: v2
Verification-Class: strict
Review-Owner: orchestrator
Part of: 0.1.8 Beta1 stop-the-bleeding work; do not start #62/#65 from this ticket.
fix: prevent foreign reasoning IDs from poisoning Official continuation
NOirBRight commentedon Aug 1, 2026
已由 PR #304(merge commit 937c0c8)修复并合并:Official、store=false 边界会删除不可携带的第三方 reasoning item,保留合法 Official encrypted reasoning 和工具调用历史,避免 404/reconnect storm。