Wolverine 6.21.0 (behavior also present in 6.20 and mirrored in JasperFx's JasperFxOptions). Not a regression — a diagnosability/documentation gap that cost a full debugging session in CritterWatch (JasperFx/CritterWatch@b365a48e has the war story).
The trap
WolverineOptions.RememberedApplicationAssembly (and JasperFx's twin) is a process-wide static: the first host that falls through to determineCallingAssembly() pins the application assembly for every later host in the process that doesn't set one explicitly. In a normal app that's one host and the cache is harmless. In a test assembly that builds many hosts (xunit/vstest process), it means:
- whichever test class runs FIRST decides handler discovery's scanned assembly for every subsequent implicit host;
- conventional handlers defined in the test assembly silently vanish for the whole run when an earlier host resolved to a referenced assembly instead (
Tests.Common, the app-under-test's assembly, …);
- the visible symptom is downstream and quiet —
No routes can be determined for Envelope … (SomeMessage) at info level, null scatter/gather results;
- and it's order-dependent: tests pass filtered/in isolation, fail in full-suite runs, and can flip between builds because test-order changes with recompilation. Ours initially looked exactly like a package-bump regression.
Asks (any subset)
- Log the pinning loudly: when
establishApplicationAssembly serves RememberedApplicationAssembly to a host whose calling assembly would have resolved differently, log a warning naming both assemblies ("application assembly X reused from a previous host in this process; handler discovery will NOT scan Y — set opts.ApplicationAssembly or opts.Discovery.IncludeAssembly to override").
- Document the static in the testing docs (parallel/serial multi-host test processes) with the
opts.Discovery.IncludeAssembly(...) / explicit opts.ApplicationAssembly remedies — the troubleshooting docs cover discovery generally but not the first-host-wins static.
- Consider scoping the cache (e.g., keying by calling assembly) or an opt-out for test processes.
The wolverine-troubleshooting-message-routing AI skill's IncludeAssembly guidance is what led us to the fix; the test-parallelization skill would be a natural home for a warning about this static too.
Wolverine 6.21.0 (behavior also present in 6.20 and mirrored in JasperFx's
JasperFxOptions). Not a regression — a diagnosability/documentation gap that cost a full debugging session in CritterWatch (JasperFx/CritterWatch@b365a48e has the war story).The trap
WolverineOptions.RememberedApplicationAssembly(and JasperFx's twin) is a process-wide static: the first host that falls through todetermineCallingAssembly()pins the application assembly for every later host in the process that doesn't set one explicitly. In a normal app that's one host and the cache is harmless. In a test assembly that builds many hosts (xunit/vstest process), it means:Tests.Common, the app-under-test's assembly, …);No routes can be determined for Envelope … (SomeMessage)at info level, null scatter/gather results;Asks (any subset)
establishApplicationAssemblyservesRememberedApplicationAssemblyto a host whose calling assembly would have resolved differently, log a warning naming both assemblies ("application assembly X reused from a previous host in this process; handler discovery will NOT scan Y — set opts.ApplicationAssembly or opts.Discovery.IncludeAssembly to override").opts.Discovery.IncludeAssembly(...)/ explicitopts.ApplicationAssemblyremedies — the troubleshooting docs cover discovery generally but not the first-host-wins static.The
wolverine-troubleshooting-message-routingAI skill'sIncludeAssemblyguidance is what led us to the fix; the test-parallelization skill would be a natural home for a warning about this static too.