[PLAN-0058] Compono.TestDoubles: Invocation-Aware Callback Responses¶
Status: Done
Implements: ADR-0053
Goal¶
Generated doubles can compute a supported non-void method's response from its real invocation arguments through a strongly typed, AOT-safe ReturnsCallback(...) configuration.
Scope¶
Implement ADR-0053's accepted member-specific builder design. Properties, void methods, unsupported parameter shapes, bare-result async convenience overloads, and general-purpose CallInfo/argument-bag APIs remain out of scope.
Tasks¶
- Accept and index ADR-0053; create and index this plan.
- Add response-state clearing that preserves call count.
- Extend the generator model/emitter/template with callback delegates, fields, builders, and dispatch.
- Add snapshot and execution coverage across plain, matched, overloaded, DIM, required, async, delegate-returning, and closed-generic members.
- Extend the sample and Native AOT smoke tests.
- Update package, roadmap, and API-reference documentation.
- Run full build/test, packaged consumer, AOT, and alexa-vox-craft dogfood validation.
- Record verification and mark this plan Done.
Critical Files¶
src/Compono/ReturnConfig.cs— response reset without verification reset.src/Compono.Generators/Discovery/TestDoubleAnalyzer.cs— collision-safe callback identifier allocation.src/Compono.Generators/Models/TestDoubleMemberInfo.cs— resolved callback identifier projection.src/Compono.Generators/Templates/TestDouble.scriban— generated storage, member-specific builders, and dispatch.src/Compono.Generators/Emitters/TestDoubleEmitter.cs— collision-safe names and template projection.
Test Plan¶
Snapshot generated shapes, compile and execute each response/precedence path, exercise a real packaged sample and Native AOT binary, then run the full solution and the relevant dogfood consumer against freshly packed packages.
Notes¶
Implementation notes and final command results will be recorded here as work proceeds.
2026-08-30 — implementation and local verification¶
ReturnConfig<T>.ClearConfiguredResponse()clears a static response without changing its verification count. Generated builders use it when installing a callback; ordinary response methods clear the callback before delegating to the existing runtime builder.- The generator emits callback state for plain slots, ADR-0050 entries, and ADR-0049 closed-instantiation state. Matched dispatch copies the delegate while locked and invokes it after releasing the lock.
- Focused execution tests cover sync,
Task<T>,ValueTask<T>, matched entries, delegate-return values, all response transitions, null rejection, propagated exceptions with recorded calls, cross-thread reentrancy, and unchanged property/void configuration. Closed-generic callback storage has generator snapshot/compile coverage; its runtime test remains blocked by the harness rejecting the existing configuration-required informational diagnostic for that shape. dotnet build --no-restorecompleted with 0 warnings and 0 errors. Direct test hosts passed for every project/TFM reached; generator tests passed 306/306 on net10.0 and net11.0; sample tests passed 64/64; the packaged Native AOT smoke binary passed.- The full direct test-host matrix was interrupted only by the pre-existing net8.0
Compono.Logging.Tests.ConcurrencyTests.ReadsConcurrentWithWrites_NeverThrowOrCorrupthost after more than four minutes (57 tests had passed, none failed). It is unrelated to this change. - Required alexa-vox-craft dogfood validation is blocked: the available checkout at
/Users/jonasha/Repos/CSharp/alexa-vox-craftlacksDirectory.Packages.props, whichscripts/dogfood-validate.shrequires, and its pipeline test is still NSubstitute-based rather than the documented FakePipelineBehavior variant.
2026-09-02 — callback generated-name collision fix¶
- Callback delegate, builder, and plain-slot callback-field names now reserve the generated double's existing declaration names. A collision falls back to a deterministic hash suffix shared by the callback name set; a snapshot covers
FooalongsideFoo_Callback,Foo_Builder, andFoo_callbacksiblings. - The generator test project passed 308/308 on both net10.0 and net11.0. A freshly packed
Compono/Compono.TestDoublesconsumer compiled and executedReturnsCallbackfor that collision shape. scripts/dogfood-validate.sh --consumer-repo /Users/jonasha/Repos/CSharp/alexa-vox-craft --packages 'Compono Compono.TestDoubles'passed on the refreshedmaincheckout: 2,784 tests passed and 32 were skipped, with both packages resolved to the same freshly packed local version.
2026-09-02 — review validation and compatibility record¶
- Added execution coverage for ADR-0049 closed instantiations. The test allows the expected non-blocking
CMP0032configuration-required diagnostic, configures separateintandstringcallbacks, and proves each closed type uses its own callback state at runtime. - Ran the motivating
alexa-vox-craftpipeline scenario in an isolatedmain-based worktree against freshly packed localComponoandCompono.TestDoublespackages. Replacing both hand-writtenFakePipelineBehaviorinstances with generated doubles configured throughReturnsCallbackcompiled; the targeted net11.0 test passed (1/1). The complete consumer suite also passed: 2,784 tests passed and 32 were skipped, with both packages resolved to the shared freshly packed local version. - Generated output grows by about 40 lines per simple supported non-void member: a delegate, member-specific builder, callback field, dispatch branch, and changed configuration-extension return type. Parameter and generic complexity can increase line length, but the added code is fixed per member and the dispatch path remains strongly typed with no reflection or boxing.
- ADR-0053 Amendment 1 records the broader pre-1.0 source-compatibility impact and the rejected alternatives that would have preserved
ReturnConfigBuilder<T>return types.
2026-09-03 — ship validation¶
- Used the repository-pinned .NET SDK
11.0.100-preview.7.26381.103. dotnet build Compono.slnx --no-restorepassed with 0 errors and 40 existing xUnit analyzer warnings.dotnet test Compono.slnx --no-restore --no-buildpassed all 3,452 tests.- The packaged
Compono.TestDoubles.SampleTestsconsumer passed 256 tests across net8.0, net9.0, net10.0, and net11.0. - Freshly packed
ComponoandCompono.TestDoublespackages passed the nativeCompono.TestDoubles.AotSmokeTestpublish-and-run check forosx-arm64. scripts/dogfood-validate.sh --consumer-repo /Users/jonasha/Repos/CSharp/alexa-vox-craft --packages 'Compono Compono.TestDoubles'passed against fresh local package version99.0.0-local.20260903093504-26508-28626. The validator confirmed the consumer resolved that version and restored its tracked files to their pre-run state.