Skip to content

fix(desktop): wait for the transcript remount in the gesture harness - #11175

Merged
kodjima33 merged 1 commit into
mainfrom
watchdog/ci-transcript-repress-flake
Aug 6, 2026
Merged

fix(desktop): wait for the transcript remount in the gesture harness#11175
kodjima33 merged 1 commit into
mainfrom
watchdog/ci-transcript-repress-flake

Conversation

@kodjima33

@kodjima33 kodjima33 commented Aug 6, 2026

Copy link
Copy Markdown
Collaborator

Bug

ChatTranscriptGestureHarnessTests.testRePresentingTheTranscriptOpensAtTheLiveEdgeAgain is red on main (run 31071838964, commit 5fd2b60ac3 — a diff that touches no transcript code), taking Desktop Swift Static & Test Contracts and Desktop Swift Build & Tests down with it.

ChatTranscriptGestureHarnessTests.swift:128: error: XCTAssertTrue failed -
a re-presented transcript starts at the live edge (scrollTop=2733.0 of 5133.0)

This is a harness defect, not a product regression.

Root cause

scrollTop=2733.0 is byte-for-byte the position the reader's gesture had just left — not a partial or mis-settled placement. The transcript was never re-presented at all.

togglePresentation() flipped isPresented to false and back to true with a fixed pump(0.2) between them. SwiftUI commits the removal on its own update turn; when that turn lands after the fixed pump ends, the two flips coalesce into no change — nothing unmounts, onAppear never runs, and the harness then measures the same transcript the reader already scrolled.

Fix

Both halves of togglePresentation() now wait on the view hierarchy (bounded at 2s) instead of a fixed pump, and the test settles with the documented settleInitialPlacement() so its budget still outlives ChatScrollLiveEdge.initialRestoreSettlingDelays. Test-harness only; no production code touched.

Verification

  • Reproduced the exact CI signature by starving the update turn (zero-gap toggle): top=2733/5133 bottom=false. Any gap that lets the teardown commit gives top=5133/5133 bottom=true — production placement is correct.
  • Post-fix, four consecutive re-presentations all land at 5133/5133 bottom=true.
  • swift test --filter ChatTranscriptGestureHarnessTests — 14/14 pass.
  • python3 desktop/macos/scripts/check_desktop_test_quality.py — debt at baseline (19 wall-clock waits, unchanged).
  • make preflight — passed.

Product invariants affected

none

Failure-Class: none

🤖 automated by hourly watchdog — tested and merged

Review in cubic

@cubic-dev-ai cubic-dev-ai 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.

1 issue found across 1 file

Confidence score: 5/5

  • In desktop/macos/Desktop/Tests/ChatTranscriptGestureHarnessTests.swift, a waitForTranscript(mounted: true) timeout can leave scrollView pointing at a detached NSScrollView, so isAtBottom may read stale geometry and produce misleading test outcomes rather than real UI state—rebind or refresh the scroll view reference after timeout/remount before checking position.
Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="desktop/macos/Desktop/Tests/ChatTranscriptGestureHarnessTests.swift">

<violation number="1" location="desktop/macos/Desktop/Tests/ChatTranscriptGestureHarnessTests.swift:564">
P3: On a `waitForTranscript(mounted: true)` timeout, `scrollView` stays bound to the old detached `NSScrollView`, so the caller's `isAtBottom` reads frozen geometry from a view no longer in the hierarchy instead of the real (absent) transcript. The helper's doc comment claims the caller 'reports the real state' on timeout, so either fail the test on remount-timeout or clear `scrollView` so callers don't measure a stale view.</violation>
</file>

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

waitForTranscript(mounted: false)
model.isPresented = true
pump(0.2)
waitForTranscript(mounted: true)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P3: On a waitForTranscript(mounted: true) timeout, scrollView stays bound to the old detached NSScrollView, so the caller's isAtBottom reads frozen geometry from a view no longer in the hierarchy instead of the real (absent) transcript. The helper's doc comment claims the caller 'reports the real state' on timeout, so either fail the test on remount-timeout or clear scrollView so callers don't measure a stale view.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At desktop/macos/Desktop/Tests/ChatTranscriptGestureHarnessTests.swift, line 564:

<comment>On a `waitForTranscript(mounted: true)` timeout, `scrollView` stays bound to the old detached `NSScrollView`, so the caller's `isAtBottom` reads frozen geometry from a view no longer in the hierarchy instead of the real (absent) transcript. The helper's doc comment claims the caller 'reports the real state' on timeout, so either fail the test on remount-timeout or clear `scrollView` so callers don't measure a stale view.</comment>

<file context>
@@ -551,14 +551,31 @@ final class ChatTranscriptGestureHarnessTests: XCTestCase {
+      waitForTranscript(mounted: false)
       model.isPresented = true
-      pump(0.2)
+      waitForTranscript(mounted: true)
       if let discovered = Self.firstScrollView(in: hostingView) { scrollView = discovered }
     }
</file context>

`ChatTranscriptGestureHarnessTests.testRePresentingTheTranscriptOpensAtTheLiveEdgeAgain`
went red on main (run 31071838964, commit 5fd2b60, a diff that touches no
transcript code) with `scrollTop=2733.0 of 5133.0` — byte-for-byte the position
the reader's gesture had just left, not a partial or mis-settled placement.

`togglePresentation()` flipped `isPresented` false then true with a fixed 0.2s
pump between them. SwiftUI commits the removal on its own update turn; when that
turn lands after the pump ends, the two flips coalesce into no change at all —
nothing unmounts, `onAppear` never runs, and the harness then measures the
transcript the reader already scrolled. Production placement is fine: every run
where the teardown actually commits lands at the live edge.

Both halves now wait on the view hierarchy (bounded at 2s) instead of a fixed
pump, and the test settles with the documented `settleInitialPlacement()` so its
budget still outlives `ChatScrollLiveEdge.initialRestoreSettlingDelays`.

Verification:
- Reproduced the exact CI signature by starving the update turn (gap=0.0):
  `top=2733/5133 bottom=false`; any gap that commits the teardown gives
  `top=5133/5133 bottom=true`. Post-fix, four consecutive re-presentations all
  land at `5133/5133`.
- `swift test --filter ChatTranscriptGestureHarnessTests` — 14/14 pass.
- `python3 desktop/macos/scripts/check_desktop_test_quality.py` — at baseline
  (19 waits, unchanged).

Failure-Class: none
@kodjima33
kodjima33 force-pushed the watchdog/ci-transcript-repress-flake branch from d3fa5c2 to f7909da Compare August 6, 2026 13:28
@kodjima33
kodjima33 merged commit 45e9e13 into main Aug 6, 2026
27 checks passed
@kodjima33
kodjima33 deleted the watchdog/ci-transcript-repress-flake branch August 6, 2026 14:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant