Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Jan 21, 2026

PR Review Feedback - All Items Addressed ✅

1. ✅ Async Enumerator Disposal (Comment #2715001127)

Issue: Object stream implementation didn't dispose async enumerator, potentially leaking resources.

Fix: Added comprehensive try-finally block with:

  • IAsyncDisposable interface check and disposal
  • Fallback reflection-based DisposeAsync invocation
  • Proper resource cleanup matching typed Stream<TRequest, TItem> semantics

Code:

finally
{
    if (enumerator is IAsyncDisposable asyncDisposable)
    {
        await asyncDisposable.DisposeAsync();
    }
    else
    {
        var disposeAsyncMethod = enumerator.GetType().GetMethod("DisposeAsync", Type.EmptyTypes);
        if (disposeAsyncMethod != null)
        {
            var disposeResult = disposeAsyncMethod.Invoke(enumerator, null);
            if (disposeResult is ValueTask vt)
            {
                await vt;
            }
        }
    }
}

2. ✅ Fixed README Example (Comment #2715001133)

Issue: Example incorrectly used dispatcher.Create() instead of AppDispatcher.Create().

Fix: Corrected to use static factory method:

var dispatcher = AppDispatcher.Create()  // Was: dispatcher.Create()
    .Pre<Cmd>(ValidateRequest, order: 0)
    .Around<Cmd, Resp>(LoggingMiddleware, order: 1)
    // ...
    .Build();

3. ✅ Object Stream Test Coverage (Comment #2715001137)

Issue: Object-based Stream(object request) overload had no tests.

Fix: Added ObjectOverloads_Stream_DispatchesCorrectly test that:

  • Creates dispatcher with stream handler
  • Calls object-based Stream(object) overload
  • Iterates and collects all yielded items (10,11,12,13,14)
  • Validates proper async enumeration via reflection
  • Includes exception handling for debugging

Implementation: Used reflection on IAsyncEnumerator<T> interface instead of dynamic:

  • Finds IAsyncEnumerable<T> interface on result
  • Gets GetAsyncEnumerator method from interface
  • Finds IAsyncEnumerator<T> interface on enumerator
  • Invokes MoveNextAsync() and Current via reflection
  • Properly handles disposal in finally block

Test Results

  • 20 dispatcher tests passing (19 existing + 1 new)
  • 134 total generator tests passing
  • 1072 core tests passing
  • 437 example tests passing

Technical Details

Why not dynamic?

  • Initial attempt used dynamic for simpler code
  • Failed with "Missing compiler required member 'Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo.Create'"
  • Switched to pure reflection on interfaces for compatibility

Reflection Strategy:

  1. Get IAsyncEnumerable<T> interface from handler result
  2. Invoke GetAsyncEnumerator(CancellationToken) to get enumerator
  3. Get IAsyncEnumerator<T> interface from enumerator
  4. Loop: invoke MoveNextAsync(), check result, get Current
  5. Dispose via IAsyncDisposable or reflection on DisposeAsync

All review feedback addressed and validated! 🎉

Original prompt

This section details on the original issue you should resolve

<issue_title>[Feature] Source-generated message dispatcher (commands, notifications, streams) with zero PatternKit runtime dependency + dual-mode API (class-based + fluent)</issue_title>
<issue_description>## Summary

We want a source generator that produces a standalone message dispatcher for an application:

  • Commands (request → response)
  • Notifications (fan-out)
  • Streams (request → async stream of items) — first-class, not an afterthought
  • Pipelines (pre/around/post hooks)

Critical requirement

The generated output must be 100% independent of PatternKit at runtime:

  • consuming projects should be able to ship the generated dispatcher without referencing PatternKit
  • the generator package may depend on PatternKit and Roslyn, but generated .g.cs files may not

The goal is to let teams write “transpilable” / standardized message flows with minimal manual wiring, while keeping the runtime surface small, fast, and distinct.


Goals

G1 — Generated runtime has no dependency on PatternKit

  • No using PatternKit.* in emitted code
  • No generated types referencing PatternKit interfaces/delegates/helpers/collections
  • The generated output compiles as a clean unit with only BCL dependencies (and optional DI adapter packages if enabled)

G2 — First-class async and streaming

  • Command handlers are async-first (ValueTask)
  • Notification handlers are async-first (ValueTask)
  • Stream requests are native: IAsyncEnumerable<T> and streaming pipelines are supported

G3 — Dual-mode consumption

The generated dispatcher supports both:

Mode A: class-based, structured (framework-like)

  • request/handler types
  • composable pipelines (behaviors)
  • deterministic ordering
  • explicit diagnostics when invalid

Mode B: lightweight, fluent (minimal ceremony)

  • register handlers via delegates
  • module-style wiring
  • minimal generics in the app code
  • easy to read in Program.cs

G4 — AOT-friendly, low-overhead runtime

  • no reflection-based dispatch
  • no runtime scanning required
  • deterministic dispatch tables generated at compile time
  • avoid per-invocation allocations where possible

Non-goals

  • We’re not building a “kitchen sink integration platform”.
  • We’re not forcing a specific DI container.
  • We’re not requiring runtime assembly scanning.
  • We’re not trying to be API-compatible with anything else; we want our own identity.

Desired Public API (generated)

Core concepts

We want three categories of messages:

  1. Command: request → response
  2. Notification: fire-and-forget fan-out
  3. Stream: request → async stream of items

And a unified dispatcher surface:

namespace MyApp.Messaging;

// Generated, dependency-free runtime type
public sealed partial class AppDispatcher
{
    // Commands
    public ValueTask<TResponse> Send<TRequest, TResponse>(TRequest request, CancellationToken ct = default);

    // Notifications
    public ValueTask Publish<TNotification>(TNotification notification, CancellationToken ct = default);

    // Streams (first-class)
    public IAsyncEnumerable<TItem> Stream<TRequest, TItem>(TRequest request, CancellationToken ct = default);
}

Overloads and “ergonomics”

We want overloads that cover common needs and reduce ceremony, while staying distinct:

Commands

public ValueTask<TResponse> Send<TResponse>(object request, CancellationToken ct = default);
public ValueTask<object?> Send(object request, CancellationToken ct = default); // optional, controlled

Notifications

public ValueTask Publish(object notification, CancellationToken ct = default);

Streams

public IAsyncEnumerable<TItem> Stream<TItem>(object request, CancellationToken ct = default);
public IAsyncEnumerable<object?> Stream(object request, CancellationToken ct = default); // optional, controlled

Notes

  • Object-based overloads are optional, behind config flags, but they are extremely useful for bridging layers (RPC, HTTP endpoints, file-based DSL).
  • We should strongly prefer generic overloads in examples and docs.

Pipeline behavior model (commands + streams)

We want a pipeline model that can be used in both class-based and fluent modes.

Command pipeline

  • Pre hook(s): run before handler
  • Around hook(s): wrap handler invocation (compose)
  • Post hook(s): run after handler succeeds (and optionally after failure)

Proposed delegates:

public delegate ValueTask<TResponse> CommandNext<TResponse>();

public interface ICommandPipeline<TRequest, TResponse>
{
    ValueTask Pre(TRequest request, CancellationToken ct);
    ValueTask<TResponse> Around(TRequest request, CancellationToken ct, CommandNext<TResponse> next);
    ValueTask Post(TRequest request, TResponse response, CancellationToken ct);

    // Optional error hook
    Valu...

</details>



<!-- START COPILOT CODING AGENT SUFFIX -->

- Fixes JerrettDavis/PatternKit#43

<!-- START COPILOT CODING AGENT TIPS -->
---

💬 We'd love your input! Share your thoughts on Copilot coding agent in our [2 minute survey](https://gh.io/copilot-coding-agent-survey).

Copilot AI and others added 4 commits January 21, 2026 06:10
…iddleware, OnError handling, and Module system

Co-authored-by: JerrettDavis <2610199+JerrettDavis@users.noreply.github.com>
Co-authored-by: JerrettDavis <2610199+JerrettDavis@users.noreply.github.com>
…review feedback

Co-authored-by: JerrettDavis <2610199+JerrettDavis@users.noreply.github.com>
- Implemented Around middleware with proper composition
- Added OnError exception handling pipelines
- Enhanced with Stream pipelines (PreStream support)
- Added Object overloads (optional) for dynamic dispatch
- Implemented Module system for organizing handlers
- Added pipeline ordering with PipelineEntry class
- Enhanced Builder with IDispatcherBuilder interface
- All tests passing (19 dispatcher + 114 other generator tests)
- Zero PatternKit runtime dependency maintained
- Comprehensive documentation updated
- Addressed code review feedback

Co-authored-by: JerrettDavis <2610199+JerrettDavis@users.noreply.github.com>
Copilot AI changed the title [WIP] Add source-generated message dispatcher with zero PatternKit dependency feat: Source-generated mediator with zero runtime dependencies Jan 21, 2026
Copilot AI requested a review from JerrettDavis January 21, 2026 06:31
@JerrettDavis JerrettDavis marked this pull request as ready for review January 22, 2026 00:49
@github-actions
Copy link
Contributor

github-actions bot commented Jan 22, 2026

⚠️ Deprecation Warning: The deny-licenses option is deprecated for possible removal in the next major release. For more information, see issue 997.

Dependency Review

✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.

Scanned Files

None

@github-actions
Copy link
Contributor

Code Coverage

Summary
  Generated on: 01/22/2026 - 00:51:57
  Coverage date: 01/22/2026 - 00:51:11 - 01/22/2026 - 00:51:51
  Parser: MultiReport (9x Cobertura)
  Assemblies: 4
  Classes: 338
  Files: 209
  Line coverage: 80.3%
  Covered lines: 11038
  Uncovered lines: 2700
  Coverable lines: 13738
  Total lines: 35972
  Branch coverage: 71% (3279 of 4613)
  Covered branches: 3279
  Total branches: 4613
  Method coverage: 77.4% (2236 of 2887)
  Full method coverage: 72.1% (2082 of 2887)
  Covered methods: 2236
  Fully covered methods: 2082
  Total methods: 2887

PatternKit.Core                                                                                                   96.9%
  PatternKit.Behavioral.Chain.ActionChain<T>                                                                       100%
  PatternKit.Behavioral.Chain.AsyncActionChain<T>                                                                  100%
  PatternKit.Behavioral.Chain.AsyncResultChain<T1, T2>                                                            97.7%
  PatternKit.Behavioral.Chain.ResultChain<T1, T2>                                                                  100%
  PatternKit.Behavioral.Command.Command<T>                                                                         100%
  PatternKit.Behavioral.Interpreter.ActionInterpreter                                                              100%
  PatternKit.Behavioral.Interpreter.ActionInterpreter<T>                                                          96.9%
  PatternKit.Behavioral.Interpreter.ActionInterpreterBuilder<T>                                                    100%
  PatternKit.Behavioral.Interpreter.AsyncActionInterpreter                                                         100%
  PatternKit.Behavioral.Interpreter.AsyncActionInterpreter<T>                                                      100%
  PatternKit.Behavioral.Interpreter.AsyncActionInterpreterBuilder<T>                                               100%
  PatternKit.Behavioral.Interpreter.AsyncInterpreter                                                               100%
  PatternKit.Behavioral.Interpreter.AsyncInterpreter<T1, T2>                                                      96.8%
  PatternKit.Behavioral.Interpreter.AsyncInterpreterBuilder<T1, T2>                                                100%
  PatternKit.Behavioral.Interpreter.Builder<T1, T2>                                                                 96%
  PatternKit.Behavioral.Interpreter.ExpressionExtensions                                                           100%
  PatternKit.Behavioral.Interpreter.Interpreter                                                                    100%
  PatternKit.Behavioral.Interpreter.Interpreter<T1, T2>                                                           96.6%
  PatternKit.Behavioral.Interpreter.NonTerminalExpression                                                          100%
  PatternKit.Behavioral.Interpreter.TerminalExpression                                                             100%
  PatternKit.Behavioral.Iterator.AsyncFlow<T>                                                                      100%
  PatternKit.Behavioral.Iterator.AsyncFlowExtensions                                                               100%
  PatternKit.Behavioral.Iterator.AsyncReplayBuffer<T>                                                             93.6%
  PatternKit.Behavioral.Iterator.Flow<T>                                                                          94.4%
  PatternKit.Behavioral.Iterator.FlowExtensions                                                                    100%
  PatternKit.Behavioral.Iterator.ReplayableSequence<T>                                                            98.2%
  PatternKit.Behavioral.Iterator.ReplayableSequenceExtensions                                                      100%
  PatternKit.Behavioral.Iterator.SharedAsyncFlow<T>                                                                100%
  PatternKit.Behavioral.Iterator.SharedFlow<T>                                                                     100%
  PatternKit.Behavioral.Iterator.WindowSequence                                                                    100%
  PatternKit.Behavioral.Mediator.Mediator                                                                         91.9%
  PatternKit.Behavioral.Mediator.MediatorHelpers                                                                   100%
  PatternKit.Behavioral.Mediator.TaskExtensions                                                                    100%
  PatternKit.Behavioral.Memento.Memento<T>                                                                         100%
  PatternKit.Behavioral.Observer.AsyncObserver<T>                                                                 98.7%
  PatternKit.Behavioral.Observer.Observer<T>                                                                      98.2%
  PatternKit.Behavioral.State.AsyncStateMachine<T1, T2>                                                             95%
  PatternKit.Behavioral.State.StateMachine<T1, T2>                                                                  99%
  PatternKit.Behavioral.Strategy.ActionStrategy<T>                                                                  97%
  PatternKit.Behavioral.Strategy.AsyncActionStrategy<T>                                                            100%
  PatternKit.Behavioral.Strategy.AsyncStrategy<T1, T2>                                                             100%
  PatternKit.Behavioral.Strategy.Strategy<T1, T2>                                                                  100%
  PatternKit.Behavioral.Strategy.TryStrategy<T1, T2>                                                              95.8%
  PatternKit.Behavioral.Template.ActionTemplate<T>                                                                 100%
  PatternKit.Behavioral.Template.AsyncActionTemplate<T>                                                            100%
  PatternKit.Behavioral.Template.AsyncTemplate<T1, T2>                                                            97.1%
  PatternKit.Behavioral.Template.AsyncTemplateMethod<T1, T2>                                                       100%
  PatternKit.Behavioral.Template.Template<T1, T2>                                                                  100%
  PatternKit.Behavioral.Template.TemplateMethod<T1, T2>                                                            100%
  PatternKit.Behavioral.TypeDispatcher.ActionTypeDispatcher<T>                                                    91.4%
  PatternKit.Behavioral.TypeDispatcher.AsyncActionTypeDispatcher<T>                                               94.5%
  PatternKit.Behavioral.TypeDispatcher.AsyncTypeDispatcher<T1, T2>                                                94.4%
  PatternKit.Behavioral.TypeDispatcher.TypeDispatcher<T1, T2>                                                      100%
  PatternKit.Behavioral.Visitor.ActionVisitor<T>                                                                  85.7%
  PatternKit.Behavioral.Visitor.ActionVisitorBase<T>                                                               100%
  PatternKit.Behavioral.Visitor.AsyncActionVisitor<T>                                                             94.5%
  PatternKit.Behavioral.Visitor.AsyncFluentActionVisitor<T>                                                        100%
  PatternKit.Behavioral.Visitor.AsyncFluentVisitor<T1, T2>                                                         100%
  PatternKit.Behavioral.Visitor.AsyncVisitor<T1, T2>                                                              86.1%
  PatternKit.Behavioral.Visitor.FluentActionVisitor<T>                                                             100%
  PatternKit.Behavioral.Visitor.FluentVisitor<T1, T2>                                                              100%
  PatternKit.Behavioral.Visitor.Visitor<T1, T2>                                                                   91.1%
  PatternKit.Behavioral.Visitor.VisitorBase<T1, T2>                                                                100%
  PatternKit.Common.Option<T>                                                                                      100%
  PatternKit.Common.Throw                                                                                          100%
  PatternKit.Common.TryHandlerExtensions                                                                           100%
  PatternKit.Creational.AbstractFactory.AbstractFactory<T>                                                        91.6%
  PatternKit.Creational.Builder.BranchBuilder<T1, T2>                                                              100%
  PatternKit.Creational.Builder.BuilderExtensions                                                                  100%
  PatternKit.Creational.Builder.ChainBuilder<T>                                                                    100%
  PatternKit.Creational.Builder.Composer<T1, T2>                                                                   100%
  PatternKit.Creational.Builder.MutableBuilder<T>                                                                  100%
  PatternKit.Creational.Factory.Factory<T1, T2>                                                                   92.3%
  PatternKit.Creational.Factory.Factory<T1, T2, T3>                                                               92.3%
  PatternKit.Creational.Prototype.Prototype<T>                                                                     100%
  PatternKit.Creational.Prototype.Prototype<T1, T2>                                                                 90%
  PatternKit.Creational.Singleton.Singleton<T>                                                                     100%
  PatternKit.Structural.Adapter.Adapter<T1, T2>                                                                    100%
  PatternKit.Structural.Adapter.AsyncAdapter<T1, T2>                                                               100%
  PatternKit.Structural.Bridge.ActionBridge<T1, T2>                                                               90.9%
  PatternKit.Structural.Bridge.AsyncActionBridge<T1, T2>                                                          96.5%
  PatternKit.Structural.Bridge.AsyncBridge<T1, T2, T3>                                                            90.6%
  PatternKit.Structural.Bridge.Bridge<T1, T2, T3>                                                                  100%
  PatternKit.Structural.Composite.ActionComposite<T>                                                               100%
  PatternKit.Structural.Composite.AsyncActionComposite<T>                                                          100%
  PatternKit.Structural.Composite.AsyncComposite<T1, T2>                                                          97.8%
  PatternKit.Structural.Composite.Composite<T1, T2>                                                               97.3%
  PatternKit.Structural.Decorator.ActionDecorator<T>                                                               100%
  PatternKit.Structural.Decorator.AsyncActionDecorator<T>                                                          100%
  PatternKit.Structural.Decorator.AsyncDecorator<T1, T2>                                                            98%
  PatternKit.Structural.Decorator.Decorator<T1, T2>                                                               97.6%
  PatternKit.Structural.Facade.Facade<T1, T2>                                                                     88.8%
  PatternKit.Structural.Facade.TypedFacade<T>                                                                     79.4%
  PatternKit.Structural.Facade.TypedFacadeDispatchProxy<T>                                                        81.8%
  PatternKit.Structural.Facade.TypedFacadeProxyFactory<T>                                                          100%
  PatternKit.Structural.Flyweight.Flyweight<T1, T2>                                                                100%
  PatternKit.Structural.Proxy.ActionProxy<T>                                                                       100%
  PatternKit.Structural.Proxy.AsyncActionProxy<T>                                                                  100%
  PatternKit.Structural.Proxy.AsyncProxy<T1, T2>                                                                  98.6%
  PatternKit.Structural.Proxy.Proxy<T1, T2>                                                                       98.8%

PatternKit.Examples                                                                                                 65%
  PatternKit.Examples.AbstractFactoryDemo.AbstractFactoryDemo                                                     98.2%
  PatternKit.Examples.ApiGateway.Demo                                                                             97.9%
  PatternKit.Examples.ApiGateway.MiniRouter                                                                       96.6%
  PatternKit.Examples.ApiGateway.Request                                                                            75%
  PatternKit.Examples.ApiGateway.Response                                                                          100%
  PatternKit.Examples.ApiGateway.Responses                                                                         100%
  PatternKit.Examples.AsyncStateDemo.ConnectionStateDemo                                                          93.5%
  PatternKit.Examples.BridgeDemo.BridgeDemo                                                                       96.7%
  PatternKit.Examples.Chain.AuthLoggingDemo                                                                       95.2%
  PatternKit.Examples.Chain.CardProcessors                                                                         100%
  PatternKit.Examples.Chain.CardTenderStrategy                                                                    77.7%
  PatternKit.Examples.Chain.CashTenderStrategy                                                                     100%
  PatternKit.Examples.Chain.ChainStage                                                                             100%
  PatternKit.Examples.Chain.CharityRoundUpRule                                                                      50%
  PatternKit.Examples.Chain.ConfigDriven.Bundle1OffEach                                                           14.2%
  PatternKit.Examples.Chain.ConfigDriven.CardTender                                                               72.2%
  PatternKit.Examples.Chain.ConfigDriven.Cash2Pct                                                                 16.6%
  PatternKit.Examples.Chain.ConfigDriven.CashTender                                                               90.9%
  PatternKit.Examples.Chain.ConfigDriven.CharityRoundUp                                                            100%
  PatternKit.Examples.Chain.ConfigDriven.ConfigDrivenPipelineBuilderExtensions                                    94.2%
  PatternKit.Examples.Chain.ConfigDriven.ConfigDrivenPipelineDemo                                                  100%
  PatternKit.Examples.Chain.ConfigDriven.Loyalty5Pct                                                                20%
  PatternKit.Examples.Chain.ConfigDriven.NickelCashOnly                                                           77.7%
  PatternKit.Examples.Chain.ConfigDriven.PipelineOptions                                                           100%
  PatternKit.Examples.Chain.Customer                                                                               100%
  PatternKit.Examples.Chain.DeviceBus                                                                              100%
  PatternKit.Examples.Chain.GenericProcessor                                                                       100%
  PatternKit.Examples.Chain.HttpRequest                                                                            100%
  PatternKit.Examples.Chain.IRoundingRule                                                                          100%
  PatternKit.Examples.Chain.LineItem                                                                               100%
  PatternKit.Examples.Chain.MediatedTransactionPipelineDemo                                                        100%
  PatternKit.Examples.Chain.NickelCashOnlyRule                                                                     100%
  PatternKit.Examples.Chain.NoopCharityTracker                                                                     100%
  PatternKit.Examples.Chain.RoundingPipeline                                                                       100%
  PatternKit.Examples.Chain.Tender                                                                                 100%
  PatternKit.Examples.Chain.TenderRouterFactory                                                                   91.3%
  PatternKit.Examples.Chain.TransactionContext                                                                     100%
  PatternKit.Examples.Chain.TransactionPipeline                                                                    100%
  PatternKit.Examples.Chain.TransactionPipelineBuilder                                                            92.3%
  PatternKit.Examples.Chain.TxResult                                                                               100%
  PatternKit.Examples.CompositeDemo.CompositeDemo                                                                  100%
  PatternKit.Examples.EnterpriseDemo.EnterpriseOrderDemo                                                          97.1%
  PatternKit.Examples.FacadeDemo.FacadeDemo                                                                        100%
  PatternKit.Examples.FlyweightDemo.FlyweightDemo                                                                 96.9%
  PatternKit.Examples.Generators.Builders.CorporateApplicationBuilderDemo.BackgroundJobsModule                     100%
  PatternKit.Examples.Generators.Builders.CorporateApplicationBuilderDemo.CorporateApp                             100%
  PatternKit.Examples.Generators.Builders.CorporateApplicationBuilderDemo.CorporateApplication                    21.4%
  PatternKit.Examples.Generators.Builders.CorporateApplicationBuilderDemo.CorporateApplicationBuilder             52.6%
  PatternKit.Examples.Generators.Builders.CorporateApplicationBuilderDemo.CorporateApplicationBuilderExtensions   94.7%
  PatternKit.Examples.Generators.Builders.CorporateApplicationBuilderDemo.CorporateApplicationDemo                27.2%
  PatternKit.Examples.Generators.Builders.CorporateApplicationBuilderDemo.CorporateAppState                        100%
  PatternKit.Examples.Generators.Builders.CorporateApplicationBuilderDemo.InMemoryJobScheduler                     100%
  PatternKit.Examples.Generators.Builders.CorporateApplicationBuilderDemo.MessagingModule                          100%
  PatternKit.Examples.Generators.Builders.CorporateApplicationBuilderDemo.NotificationOptions                        0%
  PatternKit.Examples.Generators.Builders.CorporateApplicationBuilderDemo.ObservabilityModule                      100%
  PatternKit.Examples.Generators.Builders.CorporateApplicationBuilderDemo.QueueNotificationPublisher               100%
  PatternKit.Examples.Generators.Builders.CorporateApplicationBuilderDemo.SecretsProvider                          100%
  PatternKit.Examples.Generators.Factories.ApplicationOrchestrator                                                   0%
  PatternKit.Examples.Generators.Factories.BackgroundWorker                                                        100%
  PatternKit.Examples.Generators.Factories.ConsoleMetricsSink                                                      100%
  PatternKit.Examples.Generators.Factories.MemoryCacheProvider                                                     100%
  PatternKit.Examples.Generators.Factories.OrchestratorStepFactory                                                13.4%
  PatternKit.Examples.Generators.Factories.SeedDataStep                                                            100%
  PatternKit.Examples.Generators.Factories.ServiceModuleBootstrap                                                  100%
  PatternKit.Examples.Generators.Factories.ServiceModules                                                           44%
  PatternKit.Examples.Generators.Factories.StartWorkersStep                                                        100%
  PatternKit.Examples.Generators.Factories.WarmCacheStep                                                           100%
  PatternKit.Examples.Generators.Memento.EditorStateDemo                                                             0%
  PatternKit.Examples.Generators.Memento.EditorStateHistory                                                          0%
  PatternKit.Examples.Generators.Memento.EditorStateMemento                                                          0%
  PatternKit.Examples.Generators.Memento.GameStateDemo                                                               0%
  PatternKit.Examples.Generators.Memento.GameStateHistory                                                            0%
  PatternKit.Examples.Generators.Memento.GameStateMemento                                                            0%
  PatternKit.Examples.Generators.Strategies.IntParser                                                               60%
  PatternKit.Examples.Generators.Strategies.OrderRouter                                                           95.2%
  PatternKit.Examples.Generators.Strategies.ScoreLabeler                                                           100%
  PatternKit.Examples.Generators.Visitors.Document                                                                   0%
  PatternKit.Examples.Generators.Visitors.DocumentActionVisitorBuilder                                               0%
  PatternKit.Examples.Generators.Visitors.DocumentAsyncActionVisitorBuilder                                          0%
  PatternKit.Examples.Generators.Visitors.DocumentAsyncVisitorBuilder<T>                                             0%
  PatternKit.Examples.Generators.Visitors.DocumentProcessingDemo                                                     0%
  PatternKit.Examples.Generators.Visitors.DocumentVisitorBuilder<T>                                                  0%
  PatternKit.Examples.Generators.Visitors.MarkdownDocument                                                           0%
  PatternKit.Examples.Generators.Visitors.PdfDocument                                                                0%
  PatternKit.Examples.Generators.Visitors.SpreadsheetDocument                                                        0%
  PatternKit.Examples.Generators.Visitors.WordDocument                                                               0%
  PatternKit.Examples.InterpreterDemo.InterpreterDemo                                                             93.1%
  PatternKit.Examples.IteratorDemo.IteratorDemo                                                                   98.8%
  PatternKit.Examples.MediatorDemo.AppMediator                                                                     100%
  PatternKit.Examples.MediatorDemo.AuditLogHandler                                                                 100%
  PatternKit.Examples.MediatorDemo.BoxHelper                                                                        25%
  PatternKit.Examples.MediatorDemo.CountUpCmd                                                                      100%
  PatternKit.Examples.MediatorDemo.CountUpHandler                                                                  100%
  PatternKit.Examples.MediatorDemo.EchoCmd                                                                         100%
  PatternKit.Examples.MediatorDemo.EchoHandler                                                                     100%
  PatternKit.Examples.MediatorDemo.LoggingBehavior<T1, T2>                                                         100%
  PatternKit.Examples.MediatorDemo.MediatorAssemblyScanner                                                         100%
  PatternKit.Examples.MediatorDemo.MediatorDemoSink                                                                100%
  PatternKit.Examples.MediatorDemo.MediatorRegistry                                                                100%
  PatternKit.Examples.MediatorDemo.PingCmd                                                                         100%
  PatternKit.Examples.MediatorDemo.PingHandler                                                                     100%
  PatternKit.Examples.MediatorDemo.ServiceCollectionExtensions                                                    83.3%
  PatternKit.Examples.MediatorDemo.SumCmd                                                                          100%
  PatternKit.Examples.MediatorDemo.SumCmdBehavior                                                                  100%
  PatternKit.Examples.MediatorDemo.SumHandler                                                                      100%
  PatternKit.Examples.MediatorDemo.UserCreated                                                                     100%
  PatternKit.Examples.MediatorDemo.WelcomeEmailHandler                                                             100%
  PatternKit.Examples.MementoDemo.MementoDemo                                                                     83.5%
  PatternKit.Examples.Messaging.CreateUser                                                                           0%
  PatternKit.Examples.Messaging.DispatcherUsageExamples                                                              0%
  PatternKit.Examples.Messaging.EmailSent                                                                            0%
  PatternKit.Examples.Messaging.OrderPlaced                                                                          0%
  PatternKit.Examples.Messaging.PagedItem                                                                            0%
  PatternKit.Examples.Messaging.PagedRequest                                                                         0%
  PatternKit.Examples.Messaging.SearchQuery                                                                          0%
  PatternKit.Examples.Messaging.SearchResult                                                                         0%
  PatternKit.Examples.Messaging.SendEmail                                                                            0%
  PatternKit.Examples.Messaging.SourceGenerated.ComprehensiveMediatorDemo                                            0%
  PatternKit.Examples.Messaging.SourceGenerated.CreateCustomerCommand                                                0%
  PatternKit.Examples.Messaging.SourceGenerated.CreateCustomerHandler                                                0%
  PatternKit.Examples.Messaging.SourceGenerated.Customer                                                             0%
  PatternKit.Examples.Messaging.SourceGenerated.CustomerCreatedEvent                                                 0%
  PatternKit.Examples.Messaging.SourceGenerated.GetCustomerHandler                                                   0%
  PatternKit.Examples.Messaging.SourceGenerated.GetCustomerQuery                                                     0%
  PatternKit.Examples.Messaging.SourceGenerated.GetOrdersByCustomerHandler                                           0%
  PatternKit.Examples.Messaging.SourceGenerated.GetOrdersByCustomerQuery                                             0%
  PatternKit.Examples.Messaging.SourceGenerated.InMemoryCustomerRepository                                           0%
  PatternKit.Examples.Messaging.SourceGenerated.InMemoryLogger                                                       0%
  PatternKit.Examples.Messaging.SourceGenerated.InMemoryOrderRepository                                              0%
  PatternKit.Examples.Messaging.SourceGenerated.InMemoryProductRepository                                            0%
  PatternKit.Examples.Messaging.SourceGenerated.LoggingBehavior<T1, T2>                                              0%
  PatternKit.Examples.Messaging.SourceGenerated.MediatorServiceCollectionExtensions                                  0%
  PatternKit.Examples.Messaging.SourceGenerated.NotifyInventoryHandler                                               0%
  PatternKit.Examples.Messaging.SourceGenerated.Order                                                                0%
  PatternKit.Examples.Messaging.SourceGenerated.OrderItem                                                            0%
  PatternKit.Examples.Messaging.SourceGenerated.OrderPlacedEvent                                                     0%
  PatternKit.Examples.Messaging.SourceGenerated.PaymentProcessedEvent                                                0%
  PatternKit.Examples.Messaging.SourceGenerated.PerformanceBehavior<T1, T2>                                          0%
  PatternKit.Examples.Messaging.SourceGenerated.PlaceOrderCommand                                                    0%
  PatternKit.Examples.Messaging.SourceGenerated.PlaceOrderHandler                                                    0%
  PatternKit.Examples.Messaging.SourceGenerated.ProcessPaymentCommand                                                0%
  PatternKit.Examples.Messaging.SourceGenerated.ProcessPaymentHandler                                                0%
  PatternKit.Examples.Messaging.SourceGenerated.ProductionDispatcher                                                 0%
  PatternKit.Examples.Messaging.SourceGenerated.ProductSearchResult                                                  0%
  PatternKit.Examples.Messaging.SourceGenerated.RecordPaymentAuditHandler                                            0%
  PatternKit.Examples.Messaging.SourceGenerated.SearchProductsHandler                                                0%
  PatternKit.Examples.Messaging.SourceGenerated.SearchProductsQuery                                                  0%
  PatternKit.Examples.Messaging.SourceGenerated.SendOrderConfirmationHandler                                         0%
  PatternKit.Examples.Messaging.SourceGenerated.SendWelcomeEmailHandler                                              0%
  PatternKit.Examples.Messaging.SourceGenerated.TransactionBehavior<T1, T2>                                          0%
  PatternKit.Examples.Messaging.SourceGenerated.UpdateCustomerStatsHandler                                           0%
  PatternKit.Examples.Messaging.SourceGenerated.ValidationBehavior<T1, T2>                                           0%
  PatternKit.Examples.Messaging.UserCreated                                                                          0%
  PatternKit.Examples.Messaging.UserRegistered                                                                       0%
  PatternKit.Examples.ObserverDemo.EventHub<T>                                                                     100%
  PatternKit.Examples.ObserverDemo.LineItem                                                                        100%
  PatternKit.Examples.ObserverDemo.ObservableList<T>                                                                47%
  PatternKit.Examples.ObserverDemo.ObservableVar<T>                                                                100%
  PatternKit.Examples.ObserverDemo.ProfileViewModel                                                                100%
  PatternKit.Examples.ObserverDemo.PropertyChangedHub                                                              100%
  PatternKit.Examples.ObserverDemo.ReactiveTransaction                                                            95.4%
  PatternKit.Examples.ObserverDemo.UserEvent                                                                       100%
  PatternKit.Examples.PatternShowcase.PatternShowcase                                                             91.2%
  PatternKit.Examples.PointOfSale.CustomerInfo                                                                     100%
  PatternKit.Examples.PointOfSale.Demo                                                                            99.6%
  PatternKit.Examples.PointOfSale.OrderLineItem                                                                    100%
  PatternKit.Examples.PointOfSale.PaymentProcessorDemo                                                            95.7%
  PatternKit.Examples.PointOfSale.PaymentReceipt                                                                   100%
  PatternKit.Examples.PointOfSale.PromotionConfig                                                                  100%
  PatternKit.Examples.PointOfSale.PurchaseOrder                                                                    100%
  PatternKit.Examples.PointOfSale.ReceiptLineItem                                                                  100%
  PatternKit.Examples.PointOfSale.StoreLocation                                                                    100%
  PatternKit.Examples.Pricing.ApiPricingSource                                                                     100%
  PatternKit.Examples.Pricing.CharityRoundUpRule                                                                   100%
  PatternKit.Examples.Pricing.Coupon                                                                               100%
  PatternKit.Examples.Pricing.DbPricingSource                                                                      100%
  PatternKit.Examples.Pricing.DefaultSourceRouting                                                                83.3%
  PatternKit.Examples.Pricing.FilePricingSource                                                                    100%
  PatternKit.Examples.Pricing.LineItem                                                                             100%
  PatternKit.Examples.Pricing.Location                                                                             100%
  PatternKit.Examples.Pricing.LoyaltyMembership                                                                    100%
  PatternKit.Examples.Pricing.NickelCashOnlyRule                                                                   100%
  PatternKit.Examples.Pricing.PercentLoyaltyRule                                                                   100%
  PatternKit.Examples.Pricing.PricingContext                                                                       100%
  PatternKit.Examples.Pricing.PricingDemo                                                                         56.7%
  PatternKit.Examples.Pricing.PricingPipeline                                                                      100%
  PatternKit.Examples.Pricing.PricingPipelineBuilder                                                               100%
  PatternKit.Examples.Pricing.PricingResult                                                                        100%
  PatternKit.Examples.Pricing.RegionCategoryTaxPolicy                                                              100%
  PatternKit.Examples.Pricing.Sku                                                                                 85.7%
  PatternKit.Examples.Pricing.SourceRouter                                                                        92.3%
  PatternKit.Examples.PrototypeDemo.PrototypeDemo                                                                  100%
  PatternKit.Examples.ProxyDemo.ProxyDemo                                                                         94.5%
  PatternKit.Examples.Singleton.DeviceRegistry                                                                     100%
  PatternKit.Examples.Singleton.PosAppState                                                                        100%
  PatternKit.Examples.Singleton.PosAppStateDemo                                                                    100%
  PatternKit.Examples.Singleton.PricingCache                                                                       100%
  PatternKit.Examples.Singleton.StoreConfig                                                                        100%
  PatternKit.Examples.StateDemo.OrderStateDemo                                                                     100%
  PatternKit.Examples.Strategies.Coercion.Coercer<T>                                                              83.3%
  PatternKit.Examples.Strategies.Coercion.CoercerExtensions                                                        100%
  PatternKit.Examples.Strategies.Composed.ChannelPolicy                                                            100%
  PatternKit.Examples.Strategies.Composed.ChannelPolicyFactory                                                     100%
  PatternKit.Examples.Strategies.Composed.ComposedStrategies                                                      94.2%
  PatternKit.Examples.Strategies.Composed.SendContext                                                              100%
  PatternKit.Examples.Strategies.Composed.SendResult                                                               100%
  PatternKit.Examples.TemplateDemo.AsyncDataPipeline                                                               100%
  PatternKit.Examples.TemplateDemo.DataProcessor                                                                   100%
  PatternKit.Examples.TemplateDemo.TemplateAsyncFluentDemo                                                         100%
  PatternKit.Examples.TemplateDemo.TemplateFluentDemo                                                               90%
  PatternKit.Examples.TemplateDemo.TemplateMethodDemo                                                              100%
  PatternKit.Examples.VisitorDemo.Card                                                                             100%
  PatternKit.Examples.VisitorDemo.Cash                                                                             100%
  PatternKit.Examples.VisitorDemo.CountersHandler                                                                  100%
  PatternKit.Examples.VisitorDemo.Demo                                                                             100%
  PatternKit.Examples.VisitorDemo.GiftCard                                                                         100%
  PatternKit.Examples.VisitorDemo.ReceiptRendering                                                                 100%
  PatternKit.Examples.VisitorDemo.Routing                                                                          100%
  PatternKit.Examples.VisitorDemo.StoreCredit                                                                      100%
  PatternKit.Examples.VisitorDemo.Tender                                                                           100%
  PatternKit.Examples.VisitorDemo.Unknown                                                                          100%

PatternKit.Generators                                                                                             93.9%
  PatternKit.Generators.Builders.BuilderGenerator                                                                 96.3%
  PatternKit.Generators.Factories.FactoriesGenerator                                                              86.6%
  PatternKit.Generators.MementoGenerator                                                                          94.8%
  PatternKit.Generators.Messaging.DispatcherGenerator                                                             97.9%
  PatternKit.Generators.StrategyGenerator                                                                         93.9%
  PatternKit.Generators.VisitorGenerator                                                                          99.3%

PatternKit.Generators.Abstractions                                                                                67.9%
  PatternKit.Generators.Builders.BuilderRequiredAttribute                                                          100%
  PatternKit.Generators.Builders.GenerateBuilderAttribute                                                          100%
  PatternKit.Generators.Factories.FactoryCaseAttribute                                                             100%
  PatternKit.Generators.Factories.FactoryClassAttribute                                                            100%
  PatternKit.Generators.Factories.FactoryClassKeyAttribute                                                         100%
  PatternKit.Generators.Factories.FactoryMethodAttribute                                                           100%
  PatternKit.Generators.GenerateStrategyAttribute                                                                  100%
  PatternKit.Generators.MementoAttribute                                                                             0%
  PatternKit.Generators.MementoStrategyAttribute                                                                     0%
  PatternKit.Generators.Messaging.GenerateDispatcherAttribute                                                        0%
  PatternKit.Generators.Visitors.GenerateVisitorAttribute                                                            0%

@codecov
Copy link

codecov bot commented Jan 22, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 85.82%. Comparing base (dae4428) to head (3849811).
⚠️ Report is 1 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main      #89      +/-   ##
==========================================
+ Coverage   85.38%   85.82%   +0.44%     
==========================================
  Files         143      143              
  Lines       11890    12205     +315     
  Branches     1615     1623       +8     
==========================================
+ Hits        10152    10475     +323     
+ Misses       1329     1328       -1     
+ Partials      409      402       -7     
Flag Coverage Δ
unittests 85.82% <100.00%> (+0.44%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@github-actions
Copy link
Contributor

github-actions bot commented Jan 22, 2026

Test Results

134 tests   134 ✅  44s ⏱️
  1 suites    0 💤
  1 files      0 ❌

Results for commit 3849811.

♻️ This comment has been updated with latest results.

@github-actions
Copy link
Contributor

github-actions bot commented Jan 22, 2026

🔍 PR Validation Results

Version: ``

✅ Validation Steps

  • Build solution
  • Run tests
  • Build documentation
  • Dry-run NuGet packaging

📊 Artifacts

Dry-run artifacts have been uploaded and will be available for 7 days.


This comment was automatically generated by the PR validation workflow.

Copy link

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 extends the source-generated dispatcher to provide a richer mediator-style pipeline (Pre/Around/Post/OnError), module-based registration, and optional object-based dispatch, while keeping generated runtime code free of PatternKit dependencies. It also adds tests and documentation to validate and explain the new capabilities, including streaming and module integration.

Changes:

  • Introduces a structured pipeline system for commands (Pre, Around, Post, OnError) and Pre hooks for streams using a PipelineEntry model, with ordered composition and an ExecuteWithPipeline helper.
  • Adds optional object-based overloads for Send, Publish, and Stream, plus a module system via IModule and IDispatcherBuilder, and updates the builder to support pipeline registration, stream hooks, and module wiring.
  • Expands generator tests and the Mediator demo README to cover around middleware, error handling, stream pipelines, object overloads, and the module system.

Reviewed changes

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

File Description
test/PatternKit.Generators.Tests/DispatcherGeneratorTests.cs Adds end-to-end generator tests for around middleware, OnError handling, stream Pre hooks, object-based Send/Publish overloads, and the module system to validate the generated dispatcher behavior.
src/PatternKit.Generators/Messaging/DispatcherGenerator.cs Extends the generator to emit pipeline infrastructure (PipelineEntry, PipelineType), enhanced command execution with ordered Pre/Around/Post/OnError hooks, optional reflection-based object overloads for commands/notifications/streams, and contracts for IModule/IDispatcherBuilder.
src/PatternKit.Examples/MediatorComprehensiveDemo/README.md Updates example documentation to describe the new middleware pipeline, error handling, module system, object overloads, stream pipelines, and execution flow, with illustrative code snippets.

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

@JerrettDavis
Copy link
Owner

@copilot apply changes based on the comments in this thread

Copilot AI and others added 2 commits January 22, 2026 01:57
…t stream test (WIP)

- Added try-finally with DisposeAsync for object-based stream enumeration
- Fixed README example to use AppDispatcher.Create() instead of dispatcher.Create()
- Added test for object-based Stream overload (currently being debugged)
- Attempting to fix reflection-based async enumeration

Co-authored-by: JerrettDavis <2610199+JerrettDavis@users.noreply.github.com>
… stream test

- Added try-finally with DisposeAsync for object-based stream enumeration
- Fixed README example to use AppDispatcher.Create() instead of dispatcher.Create()
- Added ObjectOverloads_Stream_DispatchesCorrectly test with full coverage
- Used reflection on IAsyncEnumerator<T> interface for proper async enumeration
- All 134 generator tests passing (20 dispatcher tests including new one)
- All 1072 core tests and 437 example tests passing

Co-authored-by: JerrettDavis <2610199+JerrettDavis@users.noreply.github.com>
@JerrettDavis JerrettDavis merged commit a99c27d into main Jan 22, 2026
10 of 11 checks passed
@JerrettDavis JerrettDavis deleted the copilot/add-source-generated-message-dispatcher branch January 22, 2026 02:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants