You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
PR #442 (fix(selftest): drain dispatcher after UpdateLayout in Harness.Render) cut the flake rate of the five NativeDocking_* fixtures dramatically — main has been green for 8 consecutive CI runs since the merge — but did not fully eliminate the underlying race. Hit again on PR #444's CI:
not ok DockHooks_Host_Resolved - assertion failed
not ok DockHooks_Pane_TitleResolved - assertion failed
not ok DockHooks_Pane_KeyResolved - assertion failed
not ok DockHooks_IsActivePane_TrueWhenActive - assertion failed
# Total failures: 4
PR #444's changes are doc-only (templates + doc apps under docs/) plus five <snippet:...>comments in src/Reactor/Core/V1Protocol/ — byte-equivalent to no-ops for the C# compiler, cannot change runtime behavior. The failure pattern is identical to the original Mode-B cascade I diagnosed in PR #442.
A re-run of just the failed AOT job is in flight; statistically it will pass.
The four DockHooks_* asserts probe text rendered inside a Memo component nested in a DockManager pane. Pane bodies render through a WinUI TabView, which realizes the selected tab's content presenter via Normal-priority dispatcher work scheduled by the layout pass. When the harness's post-UpdateLayout dispatcher drain doesn't cover that scheduled work in time, the probe runs against an empty subtree and every initial probe fails as a cascade.
That sequence wins 99%+ of the time and is what flipped main green. The residual rate looks like a path where TabView's content realization is posted at higher than Normal priority on AOT (where the dispatcher is fast enough to drain Low without the realization being queued yet), or where the realization completes only after Loaded, which the Low yield doesn't gate.
Proposed fix — defense-in-depth
Restore the per-fixture pump-until guards I removed from the five NativeDocking_* fixtures in PR #442. The pattern is the team's established shape for deferred-event flakes (#139, #149, #152, fix/selftest-gotfocus-pump-until):
for(inti=0;i<10&&H.FindText(\"alpha-host:ok\")isnull;i++)awaitHarness.Render();H.Check(\"DockHooks_Host_Resolved\",H.FindText(\"alpha-host:ok\")is not null);
Belt + suspenders: the harness fix carries the 99% case, the per-fixture pumps catch the residual 1% AOT timing window. Combined fail rate should round to zero.
Summary
PR #442 (
fix(selftest): drain dispatcher after UpdateLayout in Harness.Render) cut the flake rate of the fiveNativeDocking_*fixtures dramatically — main has been green for 8 consecutive CI runs since the merge — but did not fully eliminate the underlying race. Hit again on PR #444's CI:PR #444's changes are doc-only (templates + doc apps under
docs/) plus five<snippet:...>comments insrc/Reactor/Core/V1Protocol/— byte-equivalent to no-ops for the C# compiler, cannot change runtime behavior. The failure pattern is identical to the original Mode-B cascade I diagnosed in PR #442.A re-run of just the failed AOT job is in flight; statistically it will pass.
Root cause (from PR #442 investigation)
The four
DockHooks_*asserts probe text rendered inside aMemocomponent nested in aDockManagerpane. Pane bodies render through a WinUITabView, which realizes the selected tab's content presenter via Normal-priority dispatcher work scheduled by the layout pass. When the harness's post-UpdateLayoutdispatcher drain doesn't cover that scheduled work in time, the probe runs against an empty subtree and every initial probe fails as a cascade.PR #442's fix (
tests/Reactor.AppTests.Host/SelfTest/Harness.cs):await WaitForIdleAsync()→UpdateLayout()→ Low-priority dispatcher yield →UpdateLayout()→Task.Delay(16)That sequence wins 99%+ of the time and is what flipped main green. The residual rate looks like a path where TabView's content realization is posted at higher than Normal priority on AOT (where the dispatcher is fast enough to drain Low without the realization being queued yet), or where the realization completes only after Loaded, which the Low yield doesn't gate.
Proposed fix — defense-in-depth
Restore the per-fixture
pump-untilguards I removed from the fiveNativeDocking_*fixtures in PR #442. The pattern is the team's established shape for deferred-event flakes (#139, #149, #152,fix/selftest-gotfocus-pump-until):Fixtures that need the guard (sentinel probe):
TabGroupRendersToTabView(NativeDockingSmokeFixture.cs:94)H.FindText(\"native-body-alpha\")DockContextHooksResolveOnRealMount(NativeDockingSmokeFixture.cs:133)H.FindText(\"alpha-host:ok\")Composition_ContentMutationFlowsToActivePane(NativeDockingCompositionFixture.cs:25)H.FindText(\"count=0\")UseEffectCleanup_BodyRemovedOnPaneClose(NativeDockingReliabilityFixture.cs:195)H.FindText(\"effect-body-p1\")DynamicallyDockedComponentPage_WithOuterShellState(NativeDockingDynamicContentFixture.cs:~624)FindControl<Button>(b => b.Name == \"PixDoc_ToolbarOpenWelcome\")CompositionDrivenDocumentsRespectKeyedReconciliationH.FindText(\"<first body sentinel>\")Belt + suspenders: the harness fix carries the 99% case, the per-fixture pumps catch the residual 1% AOT timing window. Combined fail rate should round to zero.
Validation plan
tools/flake-loop.ps1 -Iterations 30 -Project tests/Reactor.SelfTestslocally; expect 30/30.Repro / observation surface
NativeDocking_*whose initial probe targets text/control rendered throughDockManager→TabView→TabViewItem.ContentPresenterRelated
fix/selftest-gotfocus-pump-until, fix(selftest): stabilize HostControlMountFunc + Tab/RadioButtons selection flakes #139, fix(selftest): stabilize Resource_FetchedData and PasswordBox UserEditFires #149, fix(selftest): stabilize Mutation_Completed and GotFocus_FiresOnA #152 — prior applications of the pump-until pattern🤖 Filed via Claude Code