Goal mode replay: thread_goal_updated events can reference another thread and cause missing Goal/user bubbles

Open 💬 0 comments Opened Jun 24, 2026 by vu4934108-code

Summary

Some long sessions that used Goal mode contain event_msg records of
type: "thread_goal_updated" whose threadId does not match the transcript's
own session_meta.payload.id. Some get_goal tool outputs inside the transcript
also return a goal attached to a different thread.

When the IDE renderer restores such a transcript and combines normal message
records, event records, and Goal state records, it appears to sometimes hide or
drop the original user /goal ... bubble or related Goal UI history.

The raw user content usually still exists in JSONL, so this looks like a
replay/render/state-merging bug rather than data loss.

Environment

  • Component: Codex VS Code IDE extension + bundled codex app-server
  • Extension: openai.chatgpt / Codex - OpenAI's coding agent
  • Extension version: 26.5616.71553
  • Bundled CLI: codex-cli 0.142.0
  • OS: WSL2, Ubuntu 24.04.4 LTS
  • Kernel: 6.6.87.2-microsoft-standard-WSL2
  • CODEX_HOME: default ~/.codex
  • State DBs observed: ~/.codex/state_5.sqlite, ~/.codex/goals_1.sqlite, ~/.codex/logs_2.sqlite

Expected behavior

  • A transcript should not contain thread_goal_updated events for another thread.
  • get_goal should return the goal for the active thread only.
  • The IDE renderer should not hide or drop original user messages because Goal

state events are mismatched.

  • If slash commands are intentionally hidden as control events, the Goal text

should still be visible in a stable Goal UI element attached to the correct thread.

Actual behavior

Goal audit results:

  • 40 transcripts scanned.
  • 13 HIGH findings.
  • 7 MEDIUM findings.
  • Current ~/.codex/goals_1.sqlite had only 1 row, while many historical

transcripts rely on replayed thread_goal_updated events.

Representative affected session:

  • Transcript thread id: 019ebc43-5a39-7793-b560-2c69294bf46f
  • Original /goal ... user message exists in the JSONL as both:
  • response_item with payload.type = "message" and role = "user"
  • event_msg with payload.type = "user_message"
  • thread_goal_updated records in the same transcript: 3,495
  • Mismatched thread_goal_updated.threadId records: 2,942
  • Mismatched thread id observed: 019eafe2-284b-73d1-a9cd-9a962733d147
  • get_goal outputs returning the other thread id: 16
  • A create_goal call failed with:
cannot create a new goal because this thread already has a goal

Other sessions show similar patterns where:

  • Goal update events reference a different thread.
  • Some transcripts contain Goal state updates without a visible /goal command.
  • User messages exist in one local record stream but are absent from another

replay stream, making renderer behavior dependent on which source it trusts.

Reproduction outline

  1. Use Goal mode in a long-running Codex IDE session.
  2. Continue work across many turns and compactions.
  3. Open or replay other long sessions that also have Goal mode history.
  4. Inspect transcript JSONL for:
  • session_meta.payload.id
  • event_msg.payload.type == "thread_goal_updated"
  • event_msg.payload.threadId
  • response_item function_call_output from get_goal
  1. Observe that some Goal events or get_goal outputs refer to another thread id.
  2. Open the session in VS Code.
  3. Observe missing/hidden original /goal user bubbles or incorrect Goal UI state.

Suggested fix direction

  • Validate threadId on every Goal event before appending or replaying it.
  • During transcript replay, discard or quarantine Goal events whose threadId

differs from the transcript's session_meta.payload.id.

  • Make get_goal strictly scoped to the active thread/session.
  • Add regression tests for restoring multiple Goal-mode transcripts in the same

app-server process.

  • Ensure slash command hiding does not make the original Goal objective

unrecoverable from the visible UI.

Privacy note

The affected transcript contents include private project work, so I cannot
attach full raw JSONL files publicly. I can provide:

  • Redacted structural samples.
  • The audit scripts used to compute the statistics.
  • Small synthetic repro transcripts, if needed.
  • Exact local counts, versions, and stack traces.

View original on GitHub ↗