Skip to content

test(opencode/run): skip Windows-only scrollback replay failure#28261

Open
kitlangton wants to merge 1 commit into
devfrom
fix/skip-windows-scrollback-replay
Open

test(opencode/run): skip Windows-only scrollback replay failure#28261
kitlangton wants to merge 1 commit into
devfrom
fix/skip-windows-scrollback-replay

Conversation

@kitlangton
Copy link
Copy Markdown
Contributor

Summary

scrollback.surface.test.ts > "renders replayed user, reasoning, and assistant output after completion" fails reliably on Windows CI while passing on Linux and macOS. It blocks every unrelated PR through branch protection (most recently seen on #28253). Skipping the case on win32 unblocks the queue without dropping coverage on the other two platforms.

The test assertion expect(output).toContain("Thinking:") fails on Windows; the received string is "› Hello you\nSay hello.\n\nHello." — only the second paragraph of the reasoning body survives. The first paragraph (_Thinking:_ **Plan**) never makes it into the committed rows.

Investigation

The reasoning input flows through:

  1. entry.body.ts reasoningBody() rewrites "Thinking: …" to "_Thinking:_ …" and returns a code body with filetype="markdown".
  2. RunScrollbackStream.writeStreaming creates a CodeRenderable with streaming: true, drawUnstyledText: false, filetype: "markdown".
  3. During flushActive(false, false), renderable.content = active.content is set. CodeRenderable.set content short-circuits in this combination — it does not call textBuffer.setText(value) while streaming, relying on the next startHighlight() cycle to populate the buffer.
  4. await active.surface.settle() renders the surface, kicks off startHighlight() via renderSelf, awaits highlightingDone, and re-renders. With MockTreeSitterClient returning { highlights: [] }, control reaches the else this.textBuffer.setText(content) branch in startHighlight() and sets _shouldRenderTextBuffer = true.
  5. flushActive then commits rows [0, surface.height - 1) while streaming.

On Windows the row commit emerges without the first paragraph. Linux uniquely forces useThread = false in @opentui/core/testing (see testing.js line ~540), so it serializes the FFI render thread and never trips this race. macOS happens to be timing-stable despite useThread = true. Windows is not. The smoking gun is most likely either Bun's microtask scheduling on Windows or a Zig-side threading interaction during the second renderSurface() pass inside settleSurface. A real fix probably belongs in opentui — either force useThread = false for testing on Windows, or eagerly call textBuffer.setText in CodeRenderable.set content when streaming updates a non-empty body.

I spent ~1 hour tracing the streaming path through CodeRenderable and ScrollbackSurface.settle (@opentui/core/index-*.js), with a local repro that produced the expected output on macOS. Going further into the Zig/FFI render path felt out of scope for a CI-unblock change, so this PR applies the fallback discussed in the task brief: test.skipIf(process.platform === "win32") with a detailed inline TODO(windows) summarising what's been ruled in/out.

What changed

  • packages/opencode/test/cli/run/scrollback.surface.test.ts: wrap the one failing case in test.skipIf(process.platform === "win32")(...) and prepend a detailed investigation comment for the next person.

The other 12 cases in this file (which all rely on the same rendering machinery but don't hit this exact streaming-code path) continue to run on every platform.

Test plan

  • bun run test test/cli/run/scrollback.surface.test.ts — 13 pass / 0 fail on macOS (the skipped case still executes here because process.platform !== "win32").
  • bun run typecheck — clean.
  • CI Windows run on this PR should show the test reported as skipped (not failed); Linux/macOS unchanged.

The "renders replayed user, reasoning, and assistant output after
completion" test reliably fails on Windows CI while passing on Linux
and macOS, blocking unrelated PRs behind branch protection.

The failure is in the streaming CodeRenderable path: a reasoning commit
becomes a `<code filetype="markdown" streaming drawUnstyledText={false}>`
renderable, whose `set content` short-circuits the textBuffer update
during streaming and relies on the next highlight cycle to populate it.
On Windows the first paragraph (`_Thinking:_ **Plan**`) is missing from
the committed rows after `settle()`; on Linux (where `useThread` is
forced off in `@opentui/core/testing`) and macOS the rows commit
correctly.

Skipping the case on `win32` with an inline investigation summary so the
next person can pick this up without redoing the trace. The assertion
still runs on Linux and macOS CI.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant