fix(agents): avoid synthetic tool results during parallel races (#88168)#88588
Conversation
|
Codex review: needs maintainer review before merge. Reviewed May 31, 2026, 6:52 AM ET / 10:52 UTC. Summary PR surface: Source +44, Tests +71. Total +115 across 4 files. Reproducibility: no. I did not live-reproduce current main. Source inspection shows the current guard still flushes pending tool calls before a newer assistant tool-call turn, and the PR body supplies after-fix local SessionManager/repair proof for that interleaving. Review metrics: 1 noteworthy metric.
Merge readiness Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch. Rank-up moves:
Risk before merge
Maintainer options:
Next step before merge
Security Review detailsBest possible solution: Land the focused transcript fix after maintainers confirm the lock report is separate follow-up scope, then close the linked issue only for the synthetic placeholder race this PR actually resolves. Do we have a high-confidence way to reproduce the issue? No, I did not live-reproduce current main. Source inspection shows the current guard still flushes pending tool calls before a newer assistant tool-call turn, and the PR body supplies after-fix local SessionManager/repair proof for that interleaving. Is this the best way to solve the issue? Yes for the central placeholder race: the guard boundary plus repair fallback is a narrow fix in the implicated paths. The safer merge state is to make the AGENTS.md: found and applied where relevant. Codex review notes: model gpt-5.5, reasoning high; reviewed against 1e08af453a06. Label changesLabel changes:
Label justifications:
Evidence reviewedPR surface: Source +44, Tests +71. Total +115 across 4 files. View PR surface stats
Acceptance criteria:
What I checked:
Likely related people:
What the crustacean ranks mean
Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics. How this review workflow works
|
3075901 to
bf66381
Compare
|
Updated the PR body with redacted local SessionManager/transcript-repair proof after rebasing to @clawsweeper re-review |
|
🦞🧹 I asked ClawSweeper to review this item again. Re-review progress:
|
bf66381 to
19264bc
Compare
19264bc to
59d2447
Compare
|
Rebased again and refreshed the PR body/proof on head @clawsweeper re-review |
|
🦞🧹 I asked ClawSweeper to review this item again. Re-review progress:
|
steipete
left a comment
There was a problem hiding this comment.
Maintainer review: approved for the focused #88168 placeholder race fix.
What I checked:
- Diff is scoped to
src/agents/session-tool-result-guard.ts,src/agents/session-transcript-repair.ts, and focused tests. - Root cause matches current main: the guard flushes pending tool results at the new assistant tool-call boundary, which can synthesize placeholders while real parallel results are still racing.
- Fix shape is right for this surface: stop synthesizing at that race boundary when synthetic results are enabled, and let transcript repair move late real results before inserting missing-result placeholders.
- Regression coverage covers both changed paths: guard persistence behavior and replay repair ordering.
- ClawSweeper re-review is
proof: sufficient/ ready for maintainer look at head59d2447234e5f00d314a27fd091f96e329600afc.
Local proof:
git diff --check origin/main...HEADnode scripts/test-projects.mjs src/agents/session-tool-result-guard.test.ts src/agents/session-transcript-repair.test.ts-> 2 files, 73 tests passed.
CI/proof reviewed:
- Head SHA:
59d2447234e5f00d314a27fd091f96e329600afc - Live merge state:
MERGEABLE/CLEAN, no pending checks. - CI run
26710452128passed the relevant check, lint, type, build, security, and agent/runtime shards. - Real behavior proof check completed successfully at 2026-05-31T10:53:06Z.
Known proof gap:
Summary
Linked context
Closes #88168
Real behavior proof (required for external PRs)
Behavior or issue addressed: Parallel tool-call batches should not persist
[openclaw] missing tool result...placeholders before real in-flight tool results have a chance to land and be repaired into provider-valid order.Real environment tested: Local OpenClaw source checkout at
/private/tmp/openclaw-88168on macOS, branchfix/parallel-tool-result-race-88168, rebased ontof7a1d3f3f6, running the repo's real SessionManager guard path, transcript repair path, Vitest, and tsgo test runners against the changed code.Exact steps or command run after this patch:
timeout 180 node scripts/test-projects.mjs src/agents/session-tool-result-guard.test.ts src/agents/session-transcript-repair.test.ts;node --import tsx -e '<inline script using SessionManager.inMemory(), installSessionToolResultGuard(), and repairToolUseResultPairing() with late real parallel tool results>'.Evidence after fix (screenshot, recording, terminal capture, console output, redacted runtime log, linked artifact, or copied live output): After rebasing to
f7a1d3f3f6, the focused test run passed 1 Vitest shard with2 passed / 73 tests.git diff --checkexited 0. Type checking exited 0 fortimeout 240 node scripts/run-tsgo.mjs -p test/tsconfig/tsconfig.test.src.json --incremental --tsBuildInfoFile .artifacts/tsgo-cache/test-src-88168-rebased-f7a1.tsbuildinfo.Redacted local runtime/session proof from the real SessionManager guard and transcript repair paths after rebasing to
f7a1d3f3f6:{ "proof": "SessionManager guard plus transcript repair local runtime path", "base": "f7a1d3f3", "pendingAfterLateResults": [], "repairAddedSyntheticCount": 0, "repairMovedRealResults": true, "rawContainsMissingPlaceholder": false, "repairedContainsMissingPlaceholder": false, "repaired": [ { "role": "assistant", "toolCallId": null, "isError": null, "text": "no missing placeholder" }, { "role": "toolResult", "toolCallId": "call_read", "isError": false, "text": "no missing placeholder" }, { "role": "assistant", "toolCallId": null, "isError": null, "text": "no missing placeholder" }, { "role": "toolResult", "toolCallId": "call_exec", "isError": false, "text": "no missing placeholder" } ] }Observed result after fix: The SessionManager guard accepts two assistant tool-call turns followed by late real results without persisting synthetic missing-result text; transcript repair then moves the real
call_readresult beside its assistant turn and adds zero synthetic results.What was not tested: A live Anthropic Claude session with real parallel
exec/readcalls was not run from this workstation.Proof limitations or environment constraints: This uses a local SessionManager runtime invocation plus repository tests rather than live provider proof; the original production session JSONL and Anthropic credentials are not available here. The later
.jsonl.lockfield report on Synthetic 'missing tool result' entries injected for parallel tool calls on Anthropic Claude, despite real results being produced #88168 is treated as separate follow-up scope unless maintainers want it folded into this PR.Before evidence (optional but encouraged): Issue Synthetic 'missing tool result' entries injected for parallel tool calls on Anthropic Claude, despite real results being produced #88168 documents live sessions where real parallel tool side effects completed but persisted transcript history contained synthetic
[openclaw] missing tool result in session history; inserted synthetic error result for transcript repair.entries instead of the real outputs.Tests and validation
timeout 180 node scripts/test-projects.mjs src/agents/session-tool-result-guard.test.ts src/agents/session-transcript-repair.test.tstimeout 240 node scripts/run-tsgo.mjs -p test/tsconfig/tsconfig.test.src.json --incremental --tsBuildInfoFile .artifacts/tsgo-cache/test-src-88168-rebased-f7a1.tsbuildinfonode --import tsx -e '<inline script using SessionManager.inMemory(), installSessionToolResultGuard(), and repairToolUseResultPairing() with late real parallel tool results>'git diff --checkRegression coverage was added for the guard not synthesizing at the new-assistant boundary and for transcript repair moving late real results ahead of newer assistant tool calls.
Risk checklist
Did user-visible behavior change? (
Yes/No)Yes. Parallel tool-call transcripts should retain real results instead of premature synthetic error placeholders.
Did config, environment, or migration behavior change? (
Yes/No)No.
Did security, auth, secrets, network, or tool execution behavior change? (
Yes/No)No.
What is the highest-risk area?
Delaying synthetic missing-result insertion could allow a temporarily invalid raw transcript shape until repair runs.
How is that risk mitigated?
The existing non-tool-result flush path still synthesizes genuinely missing results, and transcript repair now deterministically reorders late real results or synthesizes missing siblings before replay.
Current review state
What is the next action?
Await ClawSweeper re-review and fresh CI after the rebase/proof update.
What is still waiting on author, maintainer, CI, or external proof?
CI, ClawSweeper, and maintainer review. No known author-side blocker after this proof update.
Which bot or reviewer comments were addressed?
Addressed ClawSweeper's request for redacted runtime/session proof showing late real tool results repaired without synthetic placeholders, then refreshed that proof after rebasing to
f7a1d3f3f6.