Skip to content

fix: use parentID matching instead of ID ordering for prompt loop exit and message rendering#14307

Open
MakonnenMak wants to merge 2 commits intoanomalyco:devfrom
MakonnenMak:fix/clock-skew-prompt-loop-exit
Open

fix: use parentID matching instead of ID ordering for prompt loop exit and message rendering#14307
MakonnenMak wants to merge 2 commits intoanomalyco:devfrom
MakonnenMak:fix/clock-skew-prompt-loop-exit

Conversation

@MakonnenMak
Copy link
Copy Markdown

@MakonnenMak MakonnenMak commented Feb 19, 2026

Issue for this PR

Closes #14236

Type of change

  • Bug fix
  • New feature
  • Refactor / code improvement
  • Documentation

What does this PR do?

Fixes #14236

Large # of line changes test additions.

When the client and server clocks are out of sync (e.g. browser on a local machine, server on a remote host), client-generated message IDs can sort after server-generated assistant IDs because IDs are timestamp-based. This caused two bugs:

  1. Prompt loop never exits — the exit check compared user vs assistant message IDs by sort order. With clock skew, the user ID is always "newer" so the condition never triggers, causing 15+ loop iterations instead of 1.
  2. Assistant messages not renderedSessionTurn only scanned forward from the user message index to find assistant replies. With skewed IDs, the assistant sorts before the user message and was never found.

Fix: Both checks now use parentID matching instead of relying on ID/timestamp ordering:

  • Extracted shouldExitLoop() in prompt.ts — checks lastAssistant.parentID === lastUser.id regardless of ID sort order.
  • Extracted findAssistantMessages() in find-assistant-messages.tsx — scans forward first, then backward if nothing found, matching on parentID.
  • Removed debug console.log statements added during investigation.

I was running into this on coder.com remote environments where opencode web seemingly takes minutes to get a response back or just infinitely loops.

How did you verify your code works?

  • shouldExitLoop unit tests (8 cases): normal exit, clock skew exit, tool-calls, unknown, no assistant, no finish, parentID mismatch, no user
  • findAssistantMessages unit tests (8 cases): normal ordering, clock skew ordering, no assistant, multiple assistants, parentID mismatch, scan boundaries, invalid index
  • Full opencode test suite: 1110 pass, 0 fail
  • Full app test suite: 236 pass, 0 fail

Screenshots / recordings

N/A — no UI changes, logic-only fix.

Checklist

  • I have tested my changes locally
  • I have not included unrelated changes in this PR

@github-actions github-actions bot added needs:compliance This means the issue will auto-close after 2 hours. and removed needs:compliance This means the issue will auto-close after 2 hours. labels Feb 19, 2026
@github-actions
Copy link
Copy Markdown
Contributor

Thanks for updating your PR! It now meets our contributing guidelines. 👍

@github-actions
Copy link
Copy Markdown
Contributor

The following comment was made by an LLM, it may be inaccurate:

Found one potentially related PR:

Related PR:

The current PR (14307) takes a different approach to solving clock skew problems by using parentID matching instead of relying on timestamp-based ID ordering. PR #11869 may have attempted a fix at the ID generation level rather than the matching logic level. You may want to check if #11869 was merged or closed to understand the context.

if (input.assistantMessage.error) return "stop"
return "continue"
const exitReason = needsCompaction ? "compact" : blocked ? "stop" : input.assistantMessage.error ? "stop" : "continue"
return exitReason as any
Copy link
Copy Markdown
Contributor

@alexyaroshuk alexyaroshuk Feb 19, 2026

Choose a reason for hiding this comment

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

We should avoid using 'any' for typing. See Contributing guidelines

Copy link
Copy Markdown
Author

@MakonnenMak MakonnenMak Feb 19, 2026

Choose a reason for hiding this comment

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

Fixed on latest commit thanks for flagging @alexyaroshuk . Unsure how to repro the windows e2e failure though, might it be flaky?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Seems like it was, new run with rebase passed 🙏🏾

@MakonnenMak MakonnenMak force-pushed the fix/clock-skew-prompt-loop-exit branch from 0e734cb to 6f428ed Compare February 19, 2026 18:48
@MakonnenMak MakonnenMak force-pushed the fix/clock-skew-prompt-loop-exit branch from 6f428ed to fc258ea Compare February 20, 2026 18:20
@MakonnenMak
Copy link
Copy Markdown
Author

There was a conflict with the base dev branch so I had to fix and rebase. Done ✅

@alexyaroshuk
Copy link
Copy Markdown
Contributor

can't see any more issues, lgtm

@MakonnenMak
Copy link
Copy Markdown
Author

@adamdotdevin wanted to bump for a review if you have some time 🙏🏾 currently blocking us from using opencode web on a coder.com remote dev env

@MakonnenMak
Copy link
Copy Markdown
Author

@adamdotdevin bumping again, would be great to get this out

@adamdotdevin
Copy link
Copy Markdown
Member

@rekram1-node want to get your eyes on this as well

opencode-agent bot added a commit that referenced this pull request Feb 27, 2026
opencode-agent bot added a commit that referenced this pull request Feb 27, 2026
opencode-agent bot added a commit that referenced this pull request Feb 27, 2026
opencode-agent bot added a commit that referenced this pull request Feb 27, 2026
opencode-agent bot added a commit that referenced this pull request Feb 27, 2026
opencode-agent bot added a commit that referenced this pull request Feb 27, 2026
opencode-agent bot added a commit that referenced this pull request Feb 27, 2026
opencode-agent bot added a commit that referenced this pull request Feb 27, 2026
opencode-agent bot added a commit that referenced this pull request Feb 27, 2026
opencode-agent bot added a commit that referenced this pull request Feb 27, 2026
opencode-agent bot added a commit that referenced this pull request Feb 27, 2026
opencode-agent bot added a commit that referenced this pull request Mar 2, 2026
opencode-agent bot added a commit that referenced this pull request Mar 2, 2026
opencode-agent bot added a commit that referenced this pull request Mar 2, 2026
opencode-agent bot added a commit that referenced this pull request Mar 2, 2026
opencode-agent bot added a commit that referenced this pull request Mar 2, 2026
opencode-agent bot added a commit that referenced this pull request Mar 2, 2026
opencode-agent bot added a commit that referenced this pull request Mar 2, 2026
opencode-agent bot added a commit that referenced this pull request Mar 2, 2026
opencode-agent bot added a commit that referenced this pull request Mar 2, 2026
opencode-agent bot added a commit that referenced this pull request Mar 2, 2026
opencode-agent bot added a commit that referenced this pull request Mar 2, 2026
@MakonnenMak
Copy link
Copy Markdown
Author

Sorry for repushing mid-review. There was a merge conflict with dev so repushed with a small import update

@MakonnenMak
Copy link
Copy Markdown
Author

Hey @adamdotdevin @rekram1-node, could you take another look when you get a chance? Thanks!

@MakonnenMak
Copy link
Copy Markdown
Author

Hey @adamdotdevin @rekram1-node, wanted to bump again. Thank you 🙏🏾

@sjawhar
Copy link
Copy Markdown

sjawhar commented Mar 12, 2026

We independently arrived at the same fix (parentID matching instead of ID ordering) and adopted this approach in our fork. The shouldExitLoop extraction is clean and well-tested — we also extracted a shouldWrapSystemReminder helper for the system-reminder wrapping site, following the same pattern. Both run without issues on our end and cleanly resolve the infinite loop when client/server clocks diverge. +1 for merge.

@MakonnenMak
Copy link
Copy Markdown
Author

Sorry for the noise @rekram1-node, could you take a look at this when you get a chance? It's a pretty rough experience right now with remote envs that run into this client/server clock skew problem.

@MakonnenMak
Copy link
Copy Markdown
Author

Bumping again if possible @rekram1-node , happy to chat it through on the discord as well for faster communication loop 🙏🏾

@opencode-agent
Copy link
Copy Markdown
Contributor

⚠️ Blocking Beta Release

This PR cannot be merged into the beta branch due to: Merge conflicts with dev branch

Please resolve this issue to include this PR in the next beta release.

…t and message rendering

When the client clock is ahead of the server, user message IDs (generated
client-side) sort after assistant message IDs (generated server-side).
This broke the prompt loop exit check and the UI message pairing logic.

- Extract shouldExitLoop() into a pure function that uses parentID matching
  instead of relying on ID ordering
- Extract findAssistantMessages() with forward+backward scan to handle
  messages sorted out of expected order due to clock skew
- Remove debug console.log statements added during investigation
- Add tests for both extracted functions

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@sjqwert
Copy link
Copy Markdown

sjqwert commented Apr 5, 2026

⚠️ Blocking Beta Release

This PR cannot be merged into the beta branch due to: Merge failed

Please resolve this issue to include this PR in the next beta release.

1 similar comment
@sjqwert
Copy link
Copy Markdown

sjqwert commented Apr 5, 2026

⚠️ Blocking Beta Release

This PR cannot be merged into the beta branch due to: Merge failed

Please resolve this issue to include this PR in the next beta release.

@MakonnenMak
Copy link
Copy Markdown
Author

@sjqwert on it

…t-loop-exit

# Conflicts:
#	packages/opencode/src/session/prompt.ts
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Clock skew between client and server breaks prompt loop and message rendering

6 participants