Skip to content

Polecat#108: Audit test-library projections against the source-generator-only dispatch#110

Merged
jeremydmiller merged 2 commits into
mainfrom
feature/projection-audit-108
May 19, 2026
Merged

Polecat#108: Audit test-library projections against the source-generator-only dispatch#110
jeremydmiller merged 2 commits into
mainfrom
feature/projection-audit-108

Conversation

@jeremydmiller
Copy link
Copy Markdown
Member

Closes #108.

Summary

Pre-4.0 sweep verifying that every projection type in the Polecat test libraries either gets a [GeneratedEvolver] dispatcher emitted by JasperFx.Events.SourceGenerator or deliberately bypasses that path (Evolve / EvolveAsync / DetermineActionAsync / ApplyAsync override, or non-SG dispatch via FlatTableProjection / EfCoreSingleStreamProjection).

Headline: 50 projection-shaped types audited. 41 generated ✅. 9 deliberate bypass ⚠. 0 SG-discovery gaps filed.

Two artifacts

1. docs/projection-sg-audit-108.md (commit 7af2eaf)

Full inventory table with file path, base class, method shapes, partial status, SG output file, and ✅/⚠/❌ status per projection. Split into three sections:

  • Self-aggregating doc types (27 — all ✅)
  • Projection subclasses (16 — 11 ✅, 4 ⚠ overrides + FlatTable, 1 ✅ delegates to its self-aggregating evolver)
  • EF Core projections (4 — all ⚠ deliberate bypass; EF Core integration owns its own dispatch path)

Plus a shape-coverage check confirming every emit-expected shape has at least one behavioral test in the existing Polecat suite (no new per-shape tests required — coverage already there).

2. src/Polecat.Tests/Projections/projection_sg_dispatch_audit_tests.cs (commit c62c013)

Fast-feedback regression harness — two xUnit theories that register every emit-expected test-library projection through a fresh DocumentStore and assert no InvalidProjectionException. The ctor runs Projections.DiscoverGeneratedEvolvers(...) + Projections.AssertValidity(...) before any SQL is opened — that's where the post-#276 fail-fast fires.

Passed!  - Failed: 0, Passed: 32, Skipped: 0, Total: 32, Duration: 70 ms

No IntegrationContext, no DB setup, ~70ms for all 32 rows. Each row carries a descriptive label so future xUnit failure messages identify which shape regressed (e.g. "QuestParty (Guid, has ShouldDelete — the JasperFx#298 repro)").

SG gaps filed back

None. The post-#298 fix in JasperFx.Events 2.0.0-alpha.12 (PR JasperFx/jasperfx#300) unblocked the last shape that was tripping the runtime (self-aggregating docs with ShouldDelete going through IGeneratedSyncDetermineAction). Every projection in the inventory either generates correctly or falls into the deliberate-bypass column.

Commits

  1. 7af2eaf — Audit report (docs/projection-sg-audit-108.md)
  2. c62c013 — Regression harness (src/Polecat.Tests/Projections/projection_sg_dispatch_audit_tests.cs)

Reproducing the SG-emit inspection

dotnet build polecat.slnx -c Release \
  -p:EmitCompilerGeneratedFiles=true \
  -p:CompilerGeneratedFilesOutputPath=$(pwd)/_gensg
find _gensg -path "*JasperFx.Events.SourceGenerator*" -name "*.g.cs"

🤖 Generated with Claude Code

jeremydmiller and others added 2 commits May 18, 2026 20:18
…audit report)

Pre-4.0 sweep verifying that every projection type in the Polecat test
libraries (Polecat.Tests + Polecat.EntityFrameworkCore.Tests +
Polecat.AspNetCore.Testing + Polecat.AotSmoke; DcbLoadTest has no
projections) either gets a [GeneratedEvolver] dispatcher emitted by
JasperFx.Events.SourceGenerator or deliberately bypasses that path.

Headline:
- 50 projection-shaped types inventoried
- 38 SG [GeneratedEvolver] outputs across the solution
  (27 self-aggregating-doc evolvers + 8 EventProjection partial overrides
  + 3 PartialProjection Evolver overrides + 1 TypeRegistration-only)
- 41 ✅ generated + verified
- 9 ⚠ deliberate bypass (Evolve / EvolveAsync / DetermineActionAsync /
  ApplyAsync override, or FlatTableProjection / EfCoreSingleStreamProjection
  with their own dispatch)
- 0 ❌ SG-discovery gaps filed against JasperFx#276

Reproducible with:
  dotnet build polecat.slnx -c Release \
    -p:EmitCompilerGeneratedFiles=true \
    -p:CompilerGeneratedFilesOutputPath=$(pwd)/_gensg

then inspecting _gensg/**/JasperFx.Events.SourceGenerator/**.

Includes shape-coverage check confirming every emit-expected shape has
at least one behavioral test in the existing Polecat test suite (no new
per-shape behavioral tests required — all shapes already exercised).

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

`src/Polecat.Tests/Projections/projection_sg_dispatch_audit_tests.cs` —
two xUnit theories (`self_aggregating_doc_dispatcher_resolves` +
`projection_subclass_dispatcher_resolves`) that register every
emit-expected test-library projection through a fresh `DocumentStore`
(`AutoCreate.None`, bogus connection string) and assert construction
completes without `InvalidProjectionException`.

The `DocumentStore` ctor runs
`options.Projections.DiscoverGeneratedEvolvers(...)` +
`options.Projections.AssertValidity(...)` before any SQL is touched —
that's where the post-#276 fail-fast fires when the SG silently fails
to emit a `[GeneratedEvolver]` for a registered shape. No
`IntegrationContext`, no database setup, ~70ms for all 32 rows.

Future `JasperFx.Events.SourceGenerator` regressions surface here
immediately rather than waiting for the broader test suite's slow
SQL-backed fixtures to fail with the same diagnostic across many
files. Each row carries a descriptive label so the xUnit failure
message identifies which shape regressed.

Deliberately not covered (per `docs/projection-sg-audit-108.md`'s
deliberate-bypass column):
- `CompositeOrderProjection` / `OrderShippingNotificationProjection`
  (Evolve override)
- `InlineSeProjection` (RaiseSideEffects only; delegates to the
  `InlineSeAggregate` self-aggregating evolver — which IS covered)
- `FlatTableProjection` subclasses (own `_handlers` dispatch)
- `EfCoreSingleStreamProjection` subclasses (in
  `Polecat.EntityFrameworkCore.Tests`, different inheritance chain)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@jeremydmiller jeremydmiller merged commit 36328a8 into main May 19, 2026
7 checks passed
jeremydmiller added a commit that referenced this pull request May 19, 2026
… Weasel alpha.5 + cut 4.0.0-alpha.6 (#111)

* Re-pin to current JasperFx + Weasel alphas (close the Marten gap)

Polecat was 3 alphas behind on every JasperFx package and 2 alphas behind
on Weasel; Marten Phase 2 already re-pinned to the latest matrix. This
brings Polecat in lockstep with Marten 9 + the post-PR-#306 SG fixes:

  JasperFx                          2.0.0-alpha.13 → 2.0.0-alpha.16
  JasperFx.Events                   2.0.0-alpha.12 → 2.0.0-alpha.15
  JasperFx.Events.SourceGenerator   2.0.0-alpha.5  → 2.0.0-alpha.8
  Weasel.SqlServer                  9.0.0-alpha.3  → 9.0.0-alpha.5
  Weasel.EntityFrameworkCore        9.0.0-alpha.3  → 9.0.0-alpha.5

Adds two sibling JasperFx package pins for parity with Marten's matrix
(Polecat doesn't currently reference these directly, but the pin keeps
the lockstep matrix coherent when transitive resolution surfaces them
through JasperFx / JasperFx.Events updates):

  JasperFx.RuntimeCompiler          —              → 5.0.0-alpha.4
  JasperFx.SourceGeneration         —              → 2.0.0-alpha.5

Pins the 5.x line of JasperFx.RuntimeCompiler (the active continuation
of the 4.x lineage) — NOT the parallel stale 2.0.x series Marten was
briefly on before fixing it.

Refreshes the foundation pin table in docs/migration-guide.md to match.

The post-PR-#306 SG changes (per-event wrap in DetermineActionAsync
overrides; JasperFx#305 follow-up to #303/#304) didn't trip any of
Polecat's existing projection shapes — verified via the 32-row
projection_sg_dispatch_audit_tests harness from PR #110, which stays
green against the new alphas (56ms locally).

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

* Drop removed IEventStore.TeardownExistingProjectionProgressAsync impl

JasperFx.Events 2.0.0-alpha.13/.14/.15 removed
IEventStore<,>.TeardownExistingProjectionProgressAsync from the
interface (it had been [Obsolete] in earlier alphas). Polecat's
explicit-interface implementation was wrapped in
`#pragma warning disable CS0618` to silence the obsolete warning, but
the alpha.15 removal turns that into a CS0539 build error:

  'DocumentStore.TeardownExistingProjectionProgressAsync(IEventDatabase,
   string, CancellationToken)' in explicit interface declaration is not
   found among members of the interface that can be implemented

Callers should use TeardownExistingProjectionStateAsync (the canonical
non-obsolete API, which Polecat already implements just below the
removed one).

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

* Bump Polecat to 4.0.0-alpha.6

First Polecat alpha consuming the post-Phase-2 JasperFx matrix
(JasperFx alpha.16 / JasperFx.Events alpha.15 / SourceGenerator alpha.8
/ Weasel alpha.5) — matching Marten 9.0.0-alpha.\* lockstep.

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

---------

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.

Pre-4.0: Audit every projection type in the test libraries against the source-generator-only dispatch

1 participant