Skip to content

fix: prevent stale transcript replay#77033

Merged
steipete merged 2 commits into
mainfrom
codex/fix-transcript-stale-replay
May 4, 2026
Merged

fix: prevent stale transcript replay#77033
steipete merged 2 commits into
mainfrom
codex/fix-transcript-stale-replay

Conversation

@steipete

@steipete steipete commented May 4, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Prevent context-overflow retries from replaying an inbound user message that Pi already persisted.
  • Keep WebChat agent-run live delivery transcript-read-only; Pi remains the sole owner of persisted agent-run session entries.
  • Add regressions that prove overflow retry suppression and guard against gateway-side assistant transcript mirroring.

Root Cause

The concrete bug fixed here was stale replay after context-overflow compaction. When Pi had already persisted the current inbound channel message, OpenClaw could compact and retry with the original prompt. That made the same external user message appear again in future model context.

The correct boundary is that Pi owns session persistence. OpenClaw should not synthesize assistant JSONL entries from WebChat delivery state or repair Pi transcripts from outside Pi. Earlier repair code was removed before merge; this PR only prevents OpenClaw from re-sending/re-persisting an already-written inbound turn during overflow recovery.

What Changed

  • src/agents/pi-embedded-runner/run.ts: after overflow compaction, retry from the current transcript and suppress next user-message persistence when the current inbound message was already persisted.
  • src/agents/pi-embedded-runner/run.overflow-compaction.loop.test.ts: regression for the duplicate persisted-turn replay loop.
  • src/gateway/server-methods/chat.directive-tags.test.ts: guardrails that normal WebChat agent runs do not mirror live assistant delivery into persisted JSONL.
  • CHANGELOG.md: records the user-facing stale replay fix.

Verification

  • pnpm test src/agents/pi-embedded-runner/run.overflow-compaction.loop.test.ts src/gateway/server-methods/chat.directive-tags.test.ts
  • git diff --check origin/main...HEAD
  • CI passed on the merged PR head.

Fixes #76424.

@openclaw-barnacle openclaw-barnacle Bot added gateway Gateway runtime agents Agent runtime and tooling size: L maintainer Maintainer-authored PR labels May 4, 2026
@clawsweeper

clawsweeper Bot commented May 4, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs changes before merge.

Summary
The PR updates embedded Pi runner transcript repair and compaction-retry persistence handling, adds WebChat and runner regression tests, and adds a changelog entry.

Reproducibility: yes. Source-level reproduction is high confidence: current main lacks the persisted-current-inbound compaction retry guard, and the PR head has a clear duplicate-repair path when compaction shrinks the rebuilt context below prePromptMessageCount.

Next step before merge
A narrow automated repair can address the blocking review finding by fixing the repair scan boundary and adding a focused regression on the PR branch.

Security
Cleared: The diff touches transcript runner/gateway logic, tests, and changelog text only; no dependency, workflow, secret, permission, install, package-publishing, or artifact-execution surface was introduced.

Review findings

  • [P1] Clamp the repair scan after compaction — src/agents/pi-embedded-runner/run/attempt.ts:637-638
Review details

Best possible solution:

Clamp or recompute the transcript-repair scan boundary against the post-compaction context, add a regression for compaction-shifted message counts, then complete exact-head validation and maintainer review.

Do we have a high-confidence way to reproduce the issue?

Yes. Source-level reproduction is high confidence: current main lacks the persisted-current-inbound compaction retry guard, and the PR head has a clear duplicate-repair path when compaction shrinks the rebuilt context below prePromptMessageCount.

Is this the best way to solve the issue?

No as-is. The PR direction is narrow and appropriate, but the repair duplicate-detection window must account for compaction-shifted transcript indexes before this is the best fix.

Full review comments:

  • [P1] Clamp the repair scan after compaction — src/agents/pi-embedded-runner/run/attempt.ts:637-638
    When compaction during an attempt shrinks context.messages below prePromptMessageCount, this slice is empty even if the just-generated assistant turn is already persisted. The repair then appends the same visible answer again, reintroducing duplicate assistant transcript turns on overflow-recovery paths.
    Confidence: 0.91

Overall correctness: patch is incorrect
Overall confidence: 0.9

Acceptance criteria:

  • pnpm test src/agents/pi-embedded-runner/run/attempt.test.ts src/agents/pi-embedded-runner/run.overflow-compaction.loop.test.ts src/gateway/server-methods/chat.directive-tags.test.ts
  • git diff --check origin/main...HEAD
  • pnpm check:changed on exact PR head, preferably via Testbox per repo policy

What I checked:

  • Current WebChat transcript contract: Current docs say Pi message_end persistence is canonical for normal agent runs and delivery payload mirroring must avoid duplicating Pi-written assistant turns. Public docs: docs/web/webchat.md. (docs/web/webchat.md:57, 50da306c0a78)
  • Current main compaction retry gap: Current main passes params.suppressNextUserMessagePersistence through each attempt and only switches to the continuation prompt for mid-turn preflight recovery, so it lacks the PR's persisted-current-inbound guard. (src/agents/pi-embedded-runner/run.ts:1173, 50da306c0a78)
  • PR repair scan bug: The PR scans context.messages.slice(currentTurnStartIndex); after in-attempt compaction, prePromptMessageCount can be larger than the rebuilt context, making the scan empty and allowing a duplicate assistant repair append. (src/agents/pi-embedded-runner/run/attempt.ts:637, 19614bd2bd8d)
  • Existing review comment matches the blocker: A current PR review comment from chatgpt-codex-connector[bot] reports the same compaction-shifted turn-start defect on line 638. (src/agents/pi-embedded-runner/run/attempt.ts:638, 19614bd2bd8d)
  • Exact-head CI still pending: Public check-runs for head 19614bd showed most checks green but checks-node-agentic-control-plane-runtime still in progress at inspection time. (19614bd2bd8d)
  • Feature history: Recent history ties the area to Peter Steinberger's WebChat transcript docs and embedded-runner work, plus Dash's duplicate user persistence suppression on fallback retries. (src/agents/pi-embedded-runner/run.ts:1173, 50da306c0a78)

Likely related people:

  • steipete: Recent current-main commits touch WebChat transcript documentation, embedded runner prompt assembly, and tool-progress behavior in the same runner/gateway transcript area. (role: recent maintainer and adjacent owner; confidence: high; commits: 5d09b4b92c4d, 419bcd26f079, 786fdeb36631; files: src/agents/pi-embedded-runner/run.ts, src/agents/pi-embedded-runner/run/attempt.ts, src/gateway/server-methods/chat.ts)
  • dashhuang: The behavior appears adjacent to the recent duplicate user persistence suppression on fallback retries, which touched the same run loop, attempt, and params files. (role: introduced related retry persistence behavior; confidence: medium; commits: d35c79edd63b; files: src/agents/pi-embedded-runner/run.ts, src/agents/pi-embedded-runner/run/attempt.ts, src/agents/pi-embedded-runner/run/params.ts)

Remaining risk / open question:

  • Exact-head validation was not fully complete when inspected because one check-run was still in progress.

Codex review notes: model gpt-5.5, reasoning high; reviewed against 50da306c0a78.

@steipete steipete force-pushed the codex/fix-transcript-stale-replay branch from c40db37 to 19614bd Compare May 4, 2026 02:01
@steipete steipete marked this pull request as ready for review May 4, 2026 02:02

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 19614bd2bd

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +636 to +638
typeof params.currentTurnStartIndex === "number"
? context.messages.slice(Math.max(0, params.currentTurnStartIndex))
: context.messages;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Handle compaction-shifted turn start before transcript repair

When currentTurnStartIndex is derived from prePromptMessageCount, a successful in-attempt compaction can shrink context.messages so slice(currentTurnStartIndex) becomes empty even though the just-generated assistant turn is already persisted. In that case alreadyPresent is false and ensureVisibleAssistantTextInSessionTranscript appends a second assistant message for the same answer, reintroducing duplicated transcript turns after overflow-recovery paths. Clamp or recompute the turn start against the post-compaction context before duplicate detection.

Useful? React with 👍 / 👎.

@steipete steipete force-pushed the codex/fix-transcript-stale-replay branch from 6fe7c5a to 5d200f5 Compare May 4, 2026 04:56
@steipete steipete merged commit dcb3e64 into main May 4, 2026
107 checks passed
@steipete steipete deleted the codex/fix-transcript-stale-replay branch May 4, 2026 05:00
@steipete

steipete commented May 4, 2026

Copy link
Copy Markdown
Contributor Author

Landed via rebase onto main.

  • Gate: pnpm test src/agents/pi-embedded-runner/run.overflow-compaction.loop.test.ts src/gateway/server-methods/chat.directive-tags.test.ts; git diff --check origin/main...HEAD before push
  • Source head before merge: 5d200f5
  • Landed commits: 0fcf2c6, dcb3e64

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

Labels

agents Agent runtime and tooling gateway Gateway runtime maintainer Maintainer-authored PR size: S

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Telegram context-overflow retry replays same inbound message and delivers stale turn

1 participant