Skip to content

fix(selftest): stabilize Resource_FetchedData and PasswordBox UserEditFires#149

Merged
codemonkeychris merged 1 commit into
mainfrom
fix/selftest-flakes-resource-passwordbox
May 5, 2026
Merged

fix(selftest): stabilize Resource_FetchedData and PasswordBox UserEditFires#149
codemonkeychris merged 1 commit into
mainfrom
fix/selftest-flakes-resource-passwordbox

Conversation

@codemonkeychris
Copy link
Copy Markdown
Collaborator

Summary

Two remaining flake clusters surfaced in a 100× Reactor.AppTests.Host --self-test sweep on top of #139 (3/100 run-fail rate before; expected 0/100 after). Both are async-timing races where a single render pump isn't enough.

  • Resource_FetchedData (CovBoost_ComponentUseResource) — 2/100, runs 49 & 54. Task.Delay(10) fetcher resolves during the 200 ms wall-clock wait inside Harness.Render(200), then schedules a re-render that may not flush before Render(200) returns. Pump once more after the wall-clock wait so the queued re-render drains.
  • EchoSuppress_PasswordBox_UserEditFires — 1/100, run 24. PasswordBox.PasswordChanged can be raised via the dispatcher rather than synchronously in the setter (same shape as the TabView/RadioButtons flake fixed in fix(selftest): stabilize HostControlMountFunc + Tab/RadioButtons selection flakes #139). Pump twice between pb.Password = "typed" and the counter assertion.

Diff is +8 lines across two fixture files — no production code changed.

Test plan

  • dotnet build tests/Reactor.AppTests.Host — clean (0 warnings, 0 errors)
  • 100× selftest sweep on this branch (next PR action — will be run in a fresh context)
  • Targeted clusters report 0/100 run-fail; total fixture count remains 648/run

🤖 Generated with Claude Code

…tFires

Two flake clusters surfaced in a 100x `Reactor.AppTests.Host --self-test`
sweep on top of #139 (3/100 run-fail rate before; expected 0/100 after).

- `Resource_FetchedData` (CovBoost_ComponentUseResource): the 10ms
  Task.Delay fetcher resolves during the 200ms wall-clock wait inside
  Harness.Render(200), then schedules a re-render that may not flush
  before Render(200) returns. Pump once more after the wall-clock wait
  to drain the queued re-render.

- `EchoSuppress_PasswordBox_UserEditFires`: PasswordBox.PasswordChanged
  can be raised via the dispatcher rather than synchronously in the
  setter (same shape as the TabView/RadioButtons flake fixed in #139).
  Pump twice between `pb.Password = "typed"` and the counter assertion
  so the queued event lands.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR tightens two flaky self-tests in Reactor.AppTests.Host by adding extra render pumps where async/dispatcher-driven updates can land after the existing wait. It fits the self-test harness work from #139 by continuing to stabilize timing-sensitive fixture assertions without changing production code.

Changes:

  • Added a second Harness.Render() after mutating PasswordBox.Password so dispatcher-raised PasswordChanged events are observed before assertion.
  • Added an extra Harness.Render() after Harness.Render(200) in the UseResource fixture so the queued re-render from the async fetch completes before verification.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

File Description
tests/Reactor.AppTests.Host/SelfTest/Fixtures/EchoSuppressionFixtures.cs Stabilizes the PasswordBox echo-suppression fixture by waiting for dispatcher-delivered change events.
tests/Reactor.AppTests.Host/SelfTest/Fixtures/CoverageBoostFixtures.cs Stabilizes the UseResource fixture by draining the async re-render scheduled after the fetch completes.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@codemonkeychris codemonkeychris merged commit 1c887c2 into main May 5, 2026
13 of 14 checks passed
@codemonkeychris codemonkeychris deleted the fix/selftest-flakes-resource-passwordbox branch May 5, 2026 16:11
codemonkeychris added a commit that referenced this pull request May 5, 2026
Two flake clusters surfaced in a 100x `Reactor.AppTests.Host --self-test`
sweep on top of #149 (3/100 run-fail rate before; 0/100 after across a
100x verification sweep).

- `Mutation_Completed` (CovBoost_ComponentUseMutation): the useMutation
  RunAsync resolves during the 100ms wall-clock wait inside
  Harness.Render(100), then schedules a re-render that may not flush
  before Render(100) returns. Pump once more after the wall-clock wait
  to drain the queued re-render. Same shape as the Resource_FetchedData
  fix in #149.

- `GotFocus_FiresOnA` (PointerMod_GotLostFocusFires): TextBox.Focus()
  can raise GotFocus via the dispatcher rather than synchronously
  (same shape as the TabView/RadioButtons/PasswordBox flakes fixed in
  #139/#149). Pump twice between Focus() and the counter assertion so
  the queued event lands. Apply to both focus transitions in the
  fixture.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
codemonkeychris added a commit that referenced this pull request May 5, 2026
Flake surfaced in CI (run 25404199901 on PR #154):

  not ok InfiniteBasic_TotalKnown () - assertion failed

Same shape as #149 (Resource_FetchedData) and #152 (Mutation_Completed):
the fetcher's Task.Delay(10) resolves during a Render()'s 16ms wall-clock
breathing-room delay, then schedules an Apply continuation on the
dispatcher (which sets TotalCount inside ApplyPageResult) just after
WaitForIdleAsync returned. The sibling Page1Loaded check still passes
because pageFetches is incremented inside FetchPageAsync before it
returns, and Items.Count >= 25 is satisfied via _highestInflightEnd from
the in-flight slot — neither requires the Apply continuation to have
run.

Pump a third time to drain the queued re-render before the assertion.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
codemonkeychris added a commit that referenced this pull request May 7, 2026
The fixed two-pump guard added in #152 (and the same shape applied in
#139/#149 for TabView/RadioButtons/PasswordBox) still flaked at ~0.3%
across a 1000x sweep — 2 hits in 651 runs, both on `GotFocus_FiresOnA`.
The number of dispatcher ticks before programmatic Focus() raises
GotFocus isn't bounded, so any fixed pump count is a guess.

Replace the fixed pumps with a pump-until-counter-updates loop, capped
at 10 iterations (~200ms) to fail fast if the event genuinely never
fires. Applied to both focus transitions in the fixture.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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.

2 participants