Skip to content

Annotate DocumentStore.ProjectionReplay.cs reflective surface for AOT (closes #71)#75

Merged
jeremydmiller merged 1 commit into
mainfrom
feature/aot-projection-replay-71
May 13, 2026
Merged

Annotate DocumentStore.ProjectionReplay.cs reflective surface for AOT (closes #71)#75
jeremydmiller merged 1 commit into
mainfrom
feature/aot-projection-replay-71

Conversation

@jeremydmiller
Copy link
Copy Markdown
Member

Second Polecat AOT-pillar slice (closes #71), mirroring the methodology that landed in JasperFx #252-#255 + #260 + polecat#74.

Annotated surfaces

Member Annotation
RunProjectionForReferenceTypeAsync<TState> (private) [RequiresUnreferencedCode] + [RequiresDynamicCode] — runs the aggregator graph + STJ event deserialize
ToDomainEvent(EventRecord) (private) [RequiresUnreferencedCode] + [RequiresDynamicCode] — resolves CLR type from event name + STJ FromJson
ResolveEventClrType(string eventTypeName) (private) [RequiresUnreferencedCode] — walks AppDomain assemblies + Assembly.GetTypes()

Suppressed at explicit interface impls

Member Suppressions
IEventStore.RunProjectionAsync<TState> IL2091 + IL3050 + IL2075 + IL2026
IEventStore.RunProjectionByNameAsync IL3050 + IL2026 + IL2075

Why suppress instead of annotate

Both methods are explicit interface implementations of IEventStore (in JasperFx.Events). Adding [RequiresUnreferencedCode] to the impl would generate IL2046 because the interface contract on IEventStore.RunProjectionAsync / RunProjectionByNameAsync isn't yet annotated. The Events-side annotation is tracked in jasperfx#262; when those interfaces gain [RequiresUnreferencedCode] / [RequiresDynamicCode], the Polecat suppressions here can be replaced with matching annotations.

Justifications point at the design intent: projection step-through is a dev-time / diagnostic surface used by CritterWatch + projection replay, not a hot-path runtime API. AOT-publishing apps either avoid the surface entirely or supply a source-generated dispatcher.

Effect on the punch list

ProjectionReplay slice:  48 → 0  (closed)
Polecat total:           422 → 374  (-48)

Note the slice grew from the originally-filed 44 to 48 between issue filing and this PR — propagation from polecat#74's Serializer slice surfaced 4 new IL3050 warnings on the FromJson call site that this PR also addresses.

Verification

  • Polecat.csproj + Polecat.Tests.csproj build clean (0 errors)

Closes #71.

🤖 Generated with Claude Code

…closes #71)

Second Polecat AOT-pillar slice (polecat#71), mirroring the methodology
that landed in JasperFx #252-#255 + #260 + polecat#74.

Annotated surfaces

  RunProjectionForReferenceTypeAsync<TState>  — [RUC] + [RDC]
                                                (private; runs the aggregator
                                                 graph + STJ event deserialize)
  ToDomainEvent(EventRecord)                  — [RUC] + [RDC]
                                                (resolves CLR type from event
                                                 name + STJ FromJson)
  ResolveEventClrType(string eventTypeName)   — [RUC]
                                                (walks AppDomain assemblies
                                                 + Assembly.GetTypes)

Suppressed at explicit interface impls

  IEventStore.RunProjectionAsync<TState>      — IL2091 + IL3050 + IL2075 + IL2026
  IEventStore.RunProjectionByNameAsync        — IL3050 + IL2026 + IL2075

Why suppress instead of annotate

  Both methods are explicit interface implementations of `IEventStore`
  (in JasperFx.Events). Adding [RequiresUnreferencedCode] to the impl
  would generate IL2046 because the interface contract on
  IEventStore.RunProjectionAsync / RunProjectionByNameAsync isn't yet
  annotated. The Events-side annotation is tracked in jasperfx#262;
  when those interfaces gain [RUC] / [RDC], the Polecat suppressions
  here can be replaced with matching annotations.

  Justifications point at the design intent: projection step-through
  is a dev-time / diagnostic surface used by CritterWatch + projection
  replay, not a hot-path runtime API. AOT-publishing apps either avoid
  the surface entirely or supply a source-generated dispatcher.

Effect on the punch list (per TFM)

  ProjectionReplay slice:  48 → 0  (closed)
  Polecat total:           422 → 374  (-48)

  Note the slice grew from the originally-filed 44 to 48 between the
  issue filing and this PR — propagation from polecat#74's Serializer
  slice surfaced 4 new IL3050 warnings on the FromJson call site that
  this PR also addresses.

Verification

  Polecat.csproj + Polecat.Tests.csproj   build clean (0 errors)

Closes #71.
@jeremydmiller jeremydmiller merged commit e05634e into main May 13, 2026
6 checks passed
jeremydmiller added a commit that referenced this pull request May 13, 2026
Two updates to keep the migration-guide accurate as the 2026-wave alphas
roll forward:

- Bump the foundation-pin table to current Polecat 4 alpha versions:
  JasperFx alpha.8 → alpha.11, JasperFx.Events alpha.3 → alpha.4,
  Weasel.* alpha.2 → alpha.3. Note that the alpha line is still rolling
  forward and consumers should pin all five together.

- Rewrite the AOT / codegen posture section to reflect the actual landed
  state: IsAotCompatible=true is set on the Polecat assembly (#67), and
  the reflective surfaces have been progressively annotated through #74
  (serialization), #75 (projection replay), #76 (LINQ extension/provider),
  and #77 (storage / registry / event-store explorer). Link out to the
  cross-stack "Publishing AOT with JasperFx" guide on jasperfx.github.io
  for the end-to-end walkthrough.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
jeremydmiller added a commit that referenced this pull request May 13, 2026
Fifth slice in Polecat's AOT-pillar (jasperfx#213) cleanup, following the
Serializer (#74), ProjectionReplay (#75), LINQ (#76), and Storage/Registry
(#77) slices that have landed on main.

The patching subsystem reflects on the document's property expressions to
build JSON path strings and feeds the resulting patch values through
ISerializer.ToJson when emitting JSON_MODIFY() SQL. JsonPathHelper also
compiles small Expression.Lambda delegates to evaluate constant sub-
expressions during path resolution. Document types T flow in from
Schema.For<T>() / IDocumentSession.Patch<T>() at the registration boundary
and are preserved per the AOT publishing guide; AOT consumers supply a
source-generator-backed ISerializer impl.

Apply class-level [UnconditionalSuppressMessage] with justifications:

- Patching/PatchExpression<T>: IL2026/IL3050 (ISerializer.ToJson on
  patch values)
- Patching/PatchOperation: IL2026/IL3050 (ISerializer.ToJson when
  building JSON_MODIFY commands)
- Patching/JsonPathHelper: IL3050 (Expression.Lambda for constant
  sub-expression evaluation)

194 → 152 unique IL warnings (-42) in Polecat.csproj.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@jeremydmiller jeremydmiller deleted the feature/aot-projection-replay-71 branch May 14, 2026 15:25
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.

AOT pillar: annotate DocumentStore.ProjectionReplay.cs reflective surface

1 participant