Skip to content

Third-party reasoning item IDs poison Official continuation after a model switch #302

Closed

Description

@NOirBRight

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:

  1. Continue an existing task with Ollama Cloud deepseek-v4-flash:0731.
  2. The external Responses stream emits a reasoning item with a provider-local ID such as rs_<redacted> and no portable Official encrypted payload.
  3. Switch the same task to Official gpt-5.6-luna and continue.
  4. 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:

  1. The third-party response compatibility path hides raw reasoning text / non-Official encrypted content but preserves the upstream reasoning item and its rs_* ID.
  2. Codex persists that output item in task history.
  3. While the task remains on a third-party route, _rewrite_internal_input_items() drops/rephrases internal reasoning history, so the external turns continue successfully.
  4. After switching to Official, BEHAVIOR_OFFICIAL_CODEX_APP_HTTP_PASSTHROUGH calls official_passthrough_request_body(). That path rewrites the model, service tier, unsupported compaction items, and store=false, but does not sanitize provider-local reasoning items.
  5. _sanitize_official_reasoning_items() is bypassed by strict Official passthrough. Even on the non-passthrough Official path it only removes non-Official encrypted_content; it preserves the foreign id and reasoning item.
  6. 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_text
  • src-python/codex_proxy.py::official_passthrough_request_body
  • src-python/codex_proxy.py::_sanitize_official_reasoning_items
  • Existing routing coverage around test_official_body_removes_plaintext_reasoning_encrypted_content

Related reports

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 with store=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.py
  • tests/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 --check

report_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

  1. added
    bugSomething isn't working
    needs-triageMaintainer needs to evaluate this issue
    tier:heavyOrchestrator provider tier: heavy
    P1Priority 1: current iteration goal
    ready-for-agentFully specified, ready for an AFK agent
    and removed
    needs-triageMaintainer needs to evaluate this issue
    on Aug 1, 2026
  2. NOirBRight commented on Aug 1, 2026

    @NOirBRight
    OwnerAuthor

    Orchestrator decision-complete implementation contract

    Architecture decision is resolved for this Beta1 stop-the-bleeding fix:

    • At the Official upstream boundary, only process input history when the request is store=false.
    • For every type=reasoning item, keep the entire item only when it has a valid self-contained Official encrypted payload (encrypted_content with 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.
    • Apply the same rule to nested input containers without changing ordinary message, function_call, function_call_output, custom-tool call IDs/results, ordering, compaction handling, or other strict passthrough fields.
    • Keep the existing non-passthrough Official behavior compatible; this fix closes the strict passthrough hole rather than broadening mutation elsewhere.
    • Diagnostics may emit only a route transition/classification/count summary. Never log raw reasoning, IDs, prompts, tool arguments/results, task identifiers, credentials, or paths.

    Claimed paths/resources:

    • src-python/codex_proxy.py: Official strict request-body boundary and bounded diagnostic classification.
    • tests/test_routing.py: deterministic foreign rs_external_not_on_openai RED-to-GREEN regression plus valid Official encrypted reasoning and preservation tests.
    • Existing real-client fixture only for the bounded same-task Desktop gate; no unrelated routing changes.

    Done when:

    • The Issue RED payload no longer forwards the foreign reasoning item ID to Official store=false.
    • Valid Official encrypted reasoning remains usable across Official turns.
    • The named routing tests, Python full suite, real-client E2E harness, quality report, diff hygiene, Hosted CI / gate, and exact-SHA strict review pass.
    • Desktop 0.146 performs one third-party tool turn, switches to Official Luna, completes exactly once, and shows no 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.

  3. NOirBRight commented on Aug 1, 2026

    @NOirBRight
    OwnerAuthor

    已由 PR #304(merge commit 937c0c8)修复并合并:Official、store=false 边界会删除不可携带的第三方 reasoning item,保留合法 Official encrypted reasoning 和工具调用历史,避免 404/reconnect storm。

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    P1Priority 1: current iteration goalbugSomething isn't workingcampaign:0.1.8-beta10.1.8 Beta1 stop-the-bleeding campaignready-for-agentFully specified, ready for an AFK agenttier:heavyOrchestrator provider tier: heavy

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions