openai / openai/codex

[app][macOS] Scheduled heartbeat NOTIFY result disappears from thread after pagination or reload

Open
#41,995 3 comments 2 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

app automations bug session
Dominant language
Rust
Stars
125k
Forks
19.4k
PR merge metrics
PR metrics pending

Description

What version of the Codex App are you using?

ChatGPT/Codex desktop 26.825.51511 (build 7377).

What subscription do you have?

Pro.

What platform is your computer?

Darwin 25.3.0 arm64 arm

macOS 26.3.1 (25D2128), Apple Silicon.

What issue are you seeing?

A same-thread scheduled heartbeat runs successfully and returns a valid NOTIFY response, but its result disappears from the visible conversation after the thread is paginated, reloaded, or reopened.

The scheduler, model turn, heartbeat parser, and native notification path all succeed:

  • the scheduled turn reaches completed;
  • the final assistant item contains a valid heartbeat with <decision>NOTIFY</decision>;
  • macOS accepts and presents the native Codex notification; and
  • the local canonical thread index retains the final assistant item.

However, the canonical turn has no persisted automation input:

status = completed
first_user_item_id = null
final_agent_item_id = <present>
assistant decision = NOTIFY

Once the transient in-memory turn is gone, the thread renderer omits that completed canonical heartbeat turn. A manual/control turn with a normal user item remains visible.

Inspection of the current desktop bundle suggests a cross-component contract mismatch:

  1. The scheduled-heartbeat path starts an automation turn without persisting a visible automation user item.
  2. The canonical-history merge/filter treats a completed heartbeat assistant turn with no automation input as removable.
  3. That filter tests only whether the assistant message is a heartbeat. It does not preserve NOTIFY while suppressing DONT_NOTIFY.

The result is durable thread-history loss for both decisions. The native notification may still appear, but the notification cannot be found in the conversation afterward.

This is related to #39156, where heartbeat-attached chats are omitted from Activity even after NOTIFY. This report is narrower and reproducible inside the conversation itself: the chat remains accessible, but the scheduled heartbeat's assistant result disappears from canonical thread history.

What steps can reproduce the bug?

  1. Create a heartbeat automation attached to an existing local Codex Desktop thread.

  2. Use a prompt that always ends with a valid response such as:

    <heartbeat>
      <automation_id>repro-heartbeat</automation_id>
      <decision>NOTIFY</decision>
      <message>Heartbeat visibility regression check.</message>
    </heartbeat>
    
  3. Allow the scheduler to trigger the heartbeat naturally.

  4. Confirm that the turn completes and the native Codex notification appears.

  5. Reload, reopen, or paginate the target thread.

  6. Observe that the notification message is absent from the visible conversation.

  7. Inspect the local thread index. The completed turn and final assistant item exist, but first_user_item_id is null.

  8. As a control, send an ordinary user message that produces the same heartbeat response. That turn has a user item and remains visible.

The failure reproduced across multiple scheduled turns. Both NOTIFY and DONT_NOTIFY turns shared the same no-input canonical shape; only NOTIFY should remain visible.

What is the expected behavior?

  • A completed scheduled heartbeat with NOTIFY remains visible exactly once after reload or pagination and marks the thread as requiring attention.
  • A completed scheduled heartbeat with DONT_NOTIFY remains quiet and may be hidden.
  • Merging transient and canonical history does not duplicate a heartbeat result.
  • Ordinary turns remain unchanged.

The renderer should use the parsed heartbeat decision, not the presence or absence of a persisted user item, to decide visibility.

Additional information

A focused regression test should cover:

  1. canonical scheduled NOTIFY, no user item: visible exactly once after reload;
  2. canonical scheduled DONT_NOTIFY, no user item: hidden;
  3. transient plus canonical copies of the same heartbeat turn: visible once;
  4. ordinary completed turns: unchanged.

No private thread IDs, automation IDs, prompts, project names, repository paths, or account identifiers are included in this report.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Trace the scheduled-heartbeat path into the canonical thread-history merge/filter, focusing on how the heartbeat parser exposes NOTIFY and DONT_NOTIFY decisions and why a missing automation input causes removal. Add the focused regression coverage described in the issue, then verify reload or pagination preserves NOTIFY exactly once while hiding DONT_NOTIFY and leaving ordinary turns unchanged.

Written by the indexing model from the issue text.

Assessment

Tech stack
macos, rust
Domain
desktop, testing
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
52/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.