Unrelated test failure -- observed during fix for #1006
Failing tests:
Phantom.Workspaces.Agent.Gui.Tests.ChatOutputHtmlModelTests.Regression_BugD_OnInsert_UsesContainerPath_NotLoadAfterHardcode
Phantom.Workspaces.Agent.Gui.Tests.ChatOutputHtmlModelTests.HistoryLoad_NewestChunkInsertedFirst
Failure message:
[Test Case Cleanup Failure]: System.InvalidOperationException : The calling thread cannot access this object because a different thread owns it.
at Avalonia.Threading.Dispatcher.<VerifyAccess>g__ThrowVerifyAccess|17_0()
at Avalonia.Threading.Dispatcher.VerifyAccess()
at Avalonia.Rendering.DefaultRenderLoop.Add(IRenderLoopTask i)
at Avalonia.Rendering.Composition.Server.ServerCompositor..ctor(...)
at Avalonia.Rendering.Composition.Compositor..ctor(...)
at Avalonia.Headless.AvaloniaHeadlessPlatform.Initialize(AvaloniaHeadlessPlatformOptions opts)
at Avalonia.Headless.AvaloniaHeadlessPlatformExtensions.<>c__DisplayClass0_0.<UseHeadless>b__0()
at Avalonia.AppBuilder.SetupUnsafe()
at Avalonia.Headless.HeadlessUnitTestSession.EnsureIsolatedApplication()
No dump files were found.
Prior occurrence
This is a recurrence of #815, which was closed on 2026-07-14 (the day before this failure).
Root cause hypothesis
The Avalonia HeadlessUnitTestSession.EnsureIsolatedApplication() is called during test cleanup from a thread that does not own the Dispatcher that was used to set up the headless platform. When multiple tests run in parallel (or when xUnit reuses threads across test classes), the compositor constructor calls DefaultRenderLoop.Add which enforces thread affinity via Dispatcher.VerifyAccess(), causing the cleanup to throw. The fix from #815 did not fully prevent this from reoccurring.
Proposed solution
- Ensure
HeadlessUnitTestSession always initialises and tears down on the same dedicated STA/dispatcher thread — use a thread-local or session-scoped dispatcher that persists for the lifetime of the isolated application.
- If the session's
_dispatchTask faults, swallow the cleanup exception so it does not surface as a [Test Case Cleanup Failure] that hides the actual test result.
- Consider adding a test-parallelism limit on
Phantom.Workspaces.Agent.Gui.Tests to reduce the chance of thread-affinity races ([assembly: CollectionBehavior(MaxParallelThreads = 1)]).
Unrelated test failure -- observed during fix for #1006
Failing tests:
Phantom.Workspaces.Agent.Gui.Tests.ChatOutputHtmlModelTests.Regression_BugD_OnInsert_UsesContainerPath_NotLoadAfterHardcodePhantom.Workspaces.Agent.Gui.Tests.ChatOutputHtmlModelTests.HistoryLoad_NewestChunkInsertedFirstFailure message:
No dump files were found.
Prior occurrence
This is a recurrence of #815, which was closed on 2026-07-14 (the day before this failure).
Root cause hypothesis
The Avalonia
HeadlessUnitTestSession.EnsureIsolatedApplication()is called during test cleanup from a thread that does not own theDispatcherthat was used to set up the headless platform. When multiple tests run in parallel (or when xUnit reuses threads across test classes), the compositor constructor callsDefaultRenderLoop.Addwhich enforces thread affinity viaDispatcher.VerifyAccess(), causing the cleanup to throw. The fix from #815 did not fully prevent this from reoccurring.Proposed solution
HeadlessUnitTestSessionalways initialises and tears down on the same dedicated STA/dispatcher thread — use a thread-local or session-scoped dispatcher that persists for the lifetime of the isolated application._dispatchTaskfaults, swallow the cleanup exception so it does not surface as a[Test Case Cleanup Failure]that hides the actual test result.Phantom.Workspaces.Agent.Gui.Teststo reduce the chance of thread-affinity races ([assembly: CollectionBehavior(MaxParallelThreads = 1)]).