Skip to content

bug(ghosts): Codex text ghosts are never superseded (response id vs rollout turn id) #1231

Closed

Description

@Juliusolsson05

Found in the #1227 review (reviewer A, finding 1).

Codex ghosts are minted with turnId = the proxy response id (resp_…). Committed entries carry codexTurnId = the rollout's turn_context.turn_id (a UUID, providers/codex/renderer/transcript/rollout.ts:242). The two never match, and text blocks have no tool id to fall back on, so reconcileUpstream cannot supersede any Codex text ghost. Every one orphans 30 s later.

Refs #1225, #1227.

Activity

  1. Juliusolsson05 commented on Sep 25, 2026

    @Juliusolsson05
    OwnerAuthor

    Scope note after #1227 closed (the on-disk ghost log is being removed): this issue still matters for LIVE Codex ghosts, which reconcile can never supersede. Only the restore half is moot.

  2. Juliusolsson05 commented on Sep 25, 2026

    @Juliusolsson05
    OwnerAuthor

    Re-audit after #1235 (quality loop, 2026-09-25):

    • Restore: ghosts are now in-memory only (no on-disk log), so restored panes carry no ghosts. The "388 visible rows on restore" no longer applies.
    • Live panes: unsuperseded Codex text ghosts are still hidden only by render rules 3 and 4. That makes this a latent identity weakness, not a visible bug today, so it is lowered to P3.

    Two identity routes, both verified on a real rollout (rollout-2026-09-25T05-55-26-…):

    1. Response to turn map: every token_usage_record carries {turn_id, response_id} (33 in that rollout). A response's output items (reasoning, message, tool call) precede its usage record, and the tool output follows it. The mapper can't stamp items at ingest (no lookahead), but on a usage record the ingest sites (useIpcSubscriptions, initialHistory, reconstructSlices) can supersede ghosts whose turnId === response_id. This needs MappedTranscriptEntry to carry that fact.
    2. Item ids: every rollout response_item carries its id (msg_, rs_, ctc_), and the proxy SSE sees the same ids. Semantic blocks don't record them yet (a codex-headless package change), but they would give an exact per-block match.

    Route 2 is the more precise one.

  3. added and removed
    sev:P2Real bug with a workaround
    on Sep 25, 2026
  4. Juliusolsson05 commented on Sep 25, 2026

    @Juliusolsson05
    OwnerAuthor

    C8 hunt (2026-09-25): still reachable. Codex text ghosts carry the live response id (resp_…) as turnId, while committed entries carry the rollout turn UUID in codexTurnId, and nothing stamps the response id onto mapped entries. So Codex ghosts are never superseded; they orphan after 30 s and are hidden only by selectMergedEntries rules 3-4 (ghosts.ts:405-436).

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

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions