Skip to content

fix(ci): end the compile stall, the package test deadlock and the unreachable cell viewer that keep main red - #3126

Merged
datlechin merged 5 commits into
mainfrom
fix/ci-main-green
Sep 25, 2026
Merged

datlechin merged 5 commits into
mainfrom
fix/ci-main-green

Conversation

@datlechin

@datlechin datlechin commented Sep 24, 2026 •

Copy link
Copy Markdown
Member

macOS Tests has been red on main since 2026-09-23. Several separate defects, each hiding the next. This PR fixes them and nothing else, so main can go green before the gate is made required.

1. Build for testing stalls until the 60-minute job timeout

Every main run since 9fc22b3 was killed at 60 minutes with no output for the last 40 or more.

  • Cause: LinkedFileVersionHistoryProvider.prepareDiscard used directory and indexPath in a closure, then declared locals with the same names on the next lines. Xcode 27 resolves the closure's names to the properties. Swift 6.3 (Xcode 26.4.1, which CI pins, and 26.6) never finishes the SIL mandatory diagnostic passes on this function (DeadEndBlocksAnalysis, computeDominatedBoundaryBlocks in a sample of the stuck swift-frontend).
  • How it was found, on CI runners, because no local toolchain reproduces it:
    • The stuck compile batch was replayed one primary file at a time. 24 files compiled in 10 to 25 s; this one was still running at 300 s (run 36007690346).
    • Each function body was then replaced with fatalError() in turn. Only stubbing prepareDiscard compiled (13 s); every other variant timed out at 240 s (run 36038027990).
  • Fix: bind the two locals once, before their first use, so each name has one meaning. Behaviour is unchanged.
  • Xcode 26.6 stalls the same way (run 36029802119), so moving the pin would not fix this.

2. Package Tests hangs until the 20-minute job timeout

  • Cause: MSSQLFreeTDSConfigFileTests blocked Swift Testing's cooperative threads with untimed DispatchSemaphore.wait() while the work it waited for ran on DispatchQueue.global(). A blocked cooperative thread still counts against the global queue's per-CPU width. On a 3-vCPU runner, three such tests left the global queue no thread, and the whole run deadlocked.
  • Reproduced locally with 12 blockers on 10 cores. A sample showed every cooperative thread in semaphore_wait_trap at the three waits.
  • Fix: the three tests are async. The holder and waiter run on their own Threads, as the driver runs them on its own serial queue, and the test body awaits a latch instead of blocking.

3. Unit tests failing on main

  • DataFileFindBar's options menu named itself with .accessibilityLabel, which leaves a SwiftUI Menu nameless (MenuDisclosureIndicatorTests). It now carries the name in its Label, like the other icon-only menus.
  • PreferenceKeysGuardTests read DynamoDBRequestJSON.values(forKey:) as UserDefaults keys. values joins the calls the scan already knows are not preferences.
  • AccessibleControlNameTests required .accessibilityLabel in the same file, which contradicted the menu guard. It now counts a Label { Text(...) } as the name, the form the menu guard requires.

4. UI shard 1 failing on every run

RecentTabSwitchingUITests held Control with XCUIElement.perform(withKeyModifiers:), but the Tab inside reached the app without the modifier, so the held half failed in both attempts on 11 consecutive runs. The two taps stay, and they cover the menu key equivalent and the recency order end to end. The held gesture, the list and Escape are covered by 13 cases in RecentTabSwitcherControllerTests.

5. Package tests that measured time instead of cause

With the deadlock gone, this PR's first run reached ConnectionManagerTests:524 and failed it on a loaded runner: a cancelled connect gave up in 1.41 s against an elapsed < 1s bound. Every Package Tests failure in the last week was an assertion of this kind.

  • ConnectionManagerTests:524: the teardown stays blocked for its whole 30 s limit, so settling with CancellationError inside the wait already proves the connect gave up. The elapsed bound goes and the wait is 10 s.
  • ConnectionManagerTests:412: the timer that unblocks a broken teardown now records that it fired, and the test asserts it did not, instead of timing the disconnect.
  • SourceEditorBindingSyncTests: awaits the debounced writeback task (writebackTask is readable from tests now) instead of sleeping 300 ms.
  • SSHChannelRelayTests.drainsInOnePollRound: the read count already proves one poll round; the elapsed check is dropped.

6. UI shard 2: the inline cell viewer could not be found

QueryErrorBannerUITests.testAFailedRunAllFromAnOpenCellViewerKeepsNoHeadingFromThePreviousRun (added in #3121) failed on the first run and the retry, at "Return on the read-only cell must open its viewer". The CI screen recording shows the viewer open over the cell with 3 in it, so the app opened it and window.textViews could not reach it.

  • Cause: the inline cell viewer and editor were mounted as subviews of the NSTableView. A table publishes only its rows, columns and header to accessibility, never an arbitrary subview, so the open overlay had a parent but no path down to it from the window. XCUITest walks that path, and so does VoiceOver, so both missed the editor and the viewer. Measured in-process with the real AX API: the grid's AXTable had 4 children and no AXTextArea anywhere in the window. Appending the overlay to the table's accessibilityChildren() does not work: AppKit then fails the table's whole AXChildren with kAXErrorFailure, and the grid disappears from the tree.
  • Fix: the overlay is mounted in the grid's NSScrollView, directly above the clip view. That keeps it above every row and below the header, the scrollers and the pinned row gutter, and the scroll area now publishes it as AXScrollArea > AXTextArea. The raise-to-front code for the old placement is gone. A table outside a scroll view opens no overlay.
  • The header and the row gutter keep their focus emphasis while a cell is edited or viewed, as feat(connections): host every open connection in a single window #2097 intended. Focus is now resolved by ancestry from the table's scroll view, because the overlay is no longer inside the table.
  • CellOverlayAccessibilityTests (8 cases) covers both overlays: reachable from the window, mounted outside the table, stacked above the rows, over its cell, clipped by the grid, gone after dismiss, and the hit-test result published. With the overlay mounted back in the table, 7 of them fail.
  • CHANGELOG: "Data grid's inline cell editor and cell viewer unreachable by VoiceOver."

Verification

  • swift test --build-system native --package-path Packages/TableProCore: 1,114 Swift Testing cases passed; the MSSQL suite took 0.36 s.
  • swift test --build-system native --package-path Packages/TableProEditor: 171 XCTest cases passed. One Swift Testing case, GutterNumberOffsetTests.windowGutterKeepsItsMargin, fails on a dark-mode Mac and passes on CI; it reads pixel brightness and is not touched here.
  • Full TableProTests run on this branch: 23,529 cases, 1 failure, WorkspaceRailCellRenderingTests, which also depends on the Mac's appearance and passes on CI.
  • verify.sh test AccessibleControlNameTests MenuDisclosureIndicatorTests PreferenceKeysGuardTests GitIntegrationTests: 21 of 21 passed.
  • swiftlint lint --strict on every changed file: 0 violations.
  • This PR's own CI run is the check for the build stall: the build has to finish inside its timeout.

Sections 1 to 5 change nothing a user sees, so the only CHANGELOG entry is the accessibility fix in section 6.

Update for 0999140: run 36097535460 passed every job, macOS Tests Gate included. UI tests 2/3 ran the viewer case above (15 s) and 79 cases with 0 failures. Locally, 116 grid and overlay cases passed and SwiftLint --strict reported 0 violations on the changed files.

@datlechin datlechin changed the title fix(ci): end the compile stall and the package test deadlock that keep main red fix(ci): end the compile stall, the package test deadlock and the unreachable cell viewer that keep main red Sep 25, 2026
@datlechin
datlechin merged commit c4833e6 into main Sep 25, 2026
13 checks passed
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