fix(desktop): wait for the transcript remount in the gesture harness - #11175
Merged
Conversation
There was a problem hiding this comment.
1 issue found across 1 file
Confidence score: 5/5
- In
desktop/macos/Desktop/Tests/ChatTranscriptGestureHarnessTests.swift, awaitForTranscript(mounted: true)timeout can leavescrollViewpointing at a detachedNSScrollView, soisAtBottommay 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) |
There was a problem hiding this comment.
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
force-pushed
the
watchdog/ci-transcript-repress-flake
branch
from
August 6, 2026 13:28
d3fa5c2 to
f7909da
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Bug
ChatTranscriptGestureHarnessTests.testRePresentingTheTranscriptOpensAtTheLiveEdgeAgainis red onmain(run 31071838964, commit5fd2b60ac3— a diff that touches no transcript code), takingDesktop Swift Static & Test ContractsandDesktop Swift Build & Testsdown with it.This is a harness defect, not a product regression.
Root cause
scrollTop=2733.0is 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()flippedisPresentedtofalseand back totruewith a fixedpump(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,onAppearnever 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 documentedsettleInitialPlacement()so its budget still outlivesChatScrollLiveEdge.initialRestoreSettlingDelays. Test-harness only; no production code touched.Verification
top=2733/5133 bottom=false. Any gap that lets the teardown commit givestop=5133/5133 bottom=true— production placement is correct.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