Skip to content

[Bug]: Codex transient/fresh no-context-engine starts drop prior session context after #88262 #88352

Description

@100yenadmin

Bug type

Regression / behavior bug in the Codex app-server bridge.

Summary

After PR #88262, Codex app-server turns that cannot safely resume an existing Codex native thread can start a transient or fresh Codex thread with only the current prompt, even though OpenClaw has already loaded the mirrored session transcript.

The PR correctly tries to stop sending the mirrored OpenClaw transcript as parallel model history for normal Codex native resumes. The bug is that the same empty-history decision is now also used for the paths where there is no reliable Codex-native conversation to resume.

This means restricted Codex runs can silently lose prior conversation context unless an active OpenClaw context engine is present and successfully projects context.

Why this is high confidence

Diagram

flowchart TD
    A["OpenClaw session has prior visible messages"] --> B["run-attempt reads mirrored session history"]
    B --> C["Codex native surface disabled or dynamic tools unavailable"]
    C --> D["thread-lifecycle preserves old binding and starts transient thread"]
    D --> E["PR #88262 sets codexModelInputHistoryMessages = []"]
    E --> F["turn/start input = current prompt only"]
    F --> G["Fresh Codex thread has no prior context"]

    B -. "Before PR #88262" .-> H["shouldProjectMirroredHistoryForCodexStart"]
    H -. "forceProject / missing binding / newer visible history" .-> I["Bounded quoted context was projected into prompt"]
    I -.-> J["Transient/fresh thread retained continuity"]
Loading

Expected behavior

For a normal Codex native thread resume, OpenClaw should not duplicate the mirrored transcript into the model input. Codex owns that native thread history.

For a transient/fresh Codex start where OpenClaw intentionally does not resume the previous native thread, OpenClaw still needs a bounded continuity channel. The current prompt should either:

  • include a filtered, bounded projection of relevant OpenClaw-visible history, or
  • be routed through an active context engine that projects equivalent context, or
  • fail loudly / mark the turn as context-unavailable if continuity cannot be preserved.

The dangerous state is silent success with only the current prompt.

Actual behavior

When the native thread is not resumed, the code still uses the PR-wide codexModelInputHistoryMessages = [] decision. turn/start sends only the current prompt text.

This is not just a telemetry artifact. buildUserInput constructs the actual user input sent to Codex from promptText, and promptText remains params.prompt unless an active context engine projection ran.

Minimal reproduction shape

Add or adjust a focused test in extensions/codex/src/app-server/run-attempt.test.ts:

  1. Create a session JSONL file with at least one prior user/assistant message.
  2. Write an existing Codex app-server binding with a thread id.
  3. Configure the run so native tool surface is disabled, for example by using a restrictive tool/sandbox mode that makes shouldEnableCodexAppServerNativeToolSurface(...) return false.
  4. Do not attach an active context engine.
  5. Start the next Codex app-server attempt.
  6. Assert that the harness sees thread/start, not thread/resume.
  7. Assert that the turn/start input contains the bounded prior visible context, or assert the run reports a context-preservation failure.

With the merged code, the final assertion fails because the input is only the current prompt.

Impact

This hits the exact cases where a user would expect OpenClaw to be conservative about continuity:

  • sandboxed or restricted Codex turns,
  • dynamic-tool-unavailable turns,
  • native code surface disabled by policy,
  • fresh starts after invalid or incompatible Codex thread binding,
  • any OpenClaw install that relies on the mirrored transcript but does not have an active context engine for that run.

The model can answer confidently while missing important prior instructions, constraints, or task state. That is worse than a visible failure because it looks like a normal successful Codex response.

Why this is not asking to revert the whole PR

The PR's main goal is valid: do not blindly inject mirrored history as parallel model history into a Codex native thread that already owns its conversation.

The issue is the conflation of two different concepts:

flowchart LR
    A["Mirrored transcript as parallel model history"] -->|Should usually be empty for native Codex resume| B["codexModelInputHistoryMessages = []"]
    C["Visible OpenClaw continuity for fresh/transient starts"] -->|Still needed when no native thread is resumed| D["bounded prompt/context-engine projection"]
Loading

Suggested fix direction

Keep codexModelInputHistoryMessages = [] for actual native Codex model history, but reintroduce a separate, narrowly named continuity path for starts that cannot resume native history.

For example:

  • codexModelInputHistoryMessages: remains empty for the model's parallel history input.
  • freshThreadContinuityMessages: filtered OpenClaw-visible messages, excluding Codex mirrored transcript echoes.
  • Only project freshThreadContinuityMessages when thread/start is used without an active context-engine projection or when forceProject is true because the native surface is disabled.

The previous helper already had most of the needed policy:

  • force project for non-native starts,
  • project for missing binding,
  • project for dynamic tool mismatch,
  • project for OpenClaw-visible history newer than the binding,
  • exclude Codex mirrored transcript messages.

The likely fix is to restore that policy under a clearer name so it cannot be confused with normal native Codex model history.

Evidence checked

  • Merged PR metadata: openclaw/openclaw#88262, merge commit 530351e394a19b1dd2943cb08259657a13f90572.
  • Local audit checkout: PR head 04a4427d0c0b8f2e7bb666bbbcda5c557d033972.
  • Existing tests now assert the no-history behavior for fresh starts without active context engine:

Metadata

Metadata

Assignees

No one assigned

    Labels

    P1High-priority user-facing bug, regression, or broken workflow.clawsweeper:fix-shape-clearClawSweeper found a clear likely implementation shape for this issue.clawsweeper:queueable-fixClawSweeper marked this issue as an existing queue_fix_pr work candidate.clawsweeper:source-reproClawSweeper found a high-confidence source-level issue reproduction.impact:session-stateSession, memory, transcript, context, or agent state can drift or corrupt.issue-rating: 🦞 diamond lobsterVery strong issue quality with high-confidence source-level or clear reproduction.

    Type

    No type

    Fields

    Priority

    None yet

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions