Skip to content

Set IsAotCompatible=true on JasperFx + JasperFx.Events (#213)#247

Merged
jeremydmiller merged 1 commit into
mainfrom
feature/aot-compatible-flag-213
May 12, 2026
Merged

Set IsAotCompatible=true on JasperFx + JasperFx.Events (#213)#247
jeremydmiller merged 1 commit into
mainfrom
feature/aot-compatible-flag-213

Conversation

@jeremydmiller

Copy link
Copy Markdown
Member

First deliverable on the AOT compliance pillar for the Critter Stack 2026 wave. Sets IsAotCompatible=true on the two foundational packages so the IL2026 / IL2070 / IL2075 / IL3050 analyzers run against our own build. Reflective surfaces that still need [RequiresDynamicCode] / [RequiresUnreferencedCode] / [DynamicallyAccessedMembers] annotations surface here, not in downstream consumers' CI.

Surface

<!-- src/JasperFx/JasperFx.csproj, src/JasperFx.Events/JasperFx.Events.csproj -->
<IsAotCompatible>true</IsAotCompatible>

Behavior

  • Build succeeds on both projects. No new errors.
  • All four CI test projects pass locally on net9.0 + net10.0:
    • CoreTests — 407 passed
    • EventTests — 255 passed
    • CodegenTests — 366 passed
    • CommandLineTests — 280 passed
  • The trimming / AOT analyzer now emits a punch-list of warnings against reflective surfaces. These are tracking-only — none of them are new bugs, they're prior reflective code that the analyzer can now see because it's enabled.

Initial fallout (net9.0 baseline; net10.0 mirrors)

JasperFx — 236 warnings

Area Warnings Notes
Core/Reflection 64 ValueTypeInfo, GenericFactoryCache, TypeExtensions
CodeGeneration/Services + misc 54 ServiceProviderPlan, ServiceFamily, ArrayPlan, GeneratedType, Snapshots/SnapshotGate
CommandLine/* 46 CommandFactory, Parsing/*, Internal, DependencyInjectionCommandCreatorscope of follow-up B
Core/IoC 30 GenericConnectionScanner, DefaultConventionScanner, ImplementationMap
ServiceContainer.cs 16 Closed-generic registration paths
Core/TypeScanning 10 AssemblyFinder, AssemblyTypes
JasperFxOptions.cs 6
Misc 10 Resources, Environment, Descriptors, CommandLineHostingExtensions

JasperFx.Events — 134 warnings

Area Warnings Notes
Projections/EventProjectionApplication.cs 30 Method-table reflection
Aggregation/* 60 JasperFxAggregationProjectionBase, AggregateApplication.{Register,Creating,ShouldDelete,Applies}, CreateMethodCollection, ApplyMethodCollection, AggregateVersioning
Internals/MethodCollection.cs, IEventRegistry.cs 12
Misc 16 Daemon, CommandLine, StreamAction, Tags, ReflectionExtensions

Why this lands flag-only

Per the pillar definition, the goal is either AOT-clean or every dynamic surface annotated with precise [RequiresDynamicCode] / [RequiresUnreferencedCode]. Annotating ~370 warning sites in a single PR would be unreviewable; each slice is naturally a follow-up.

Immediate next steps (separate PRs, tracked under #213):

  • JasperFx.CommandLine audit — assembly-scanning for IJasperFxCommand, ~46 warnings. Already queued as the next pillar deliverable.
  • AOT-clean smoke-test consumer project in CI — pins the build green per slice once annotated.
  • Per-slice annotation passes for Core/Reflection, Core/IoC, Aggregation, Projections — best filed as follow-up issues against [Pillar] AOT compliance #213 so they can be tackled independently.

🤖 Generated with Claude Code

First deliverable on the AOT compliance pillar (#213). Flipping the
flag turns on the IL2026 / IL2070 / IL2075 / IL3050 analyzers against our
own build, so the punch list of reflective surfaces that still need
[RequiresDynamicCode] / [RequiresUnreferencedCode] / [DynamicallyAccessedMembers]
annotations surfaces in our CI rather than downstream consumers'. Tests still
pass on net9.0 + net10.0 across CoreTests (407), EventTests (255),
CodegenTests (366), and CommandLineTests (280).

Initial fallout (net9.0; net10.0 mirrors):

JasperFx — 236 warnings
  104 Core (64 Reflection, 30 IoC, 10 TypeScanning)
   54 CodeGeneration (22 Services, 8 Snapshots, 8 GeneratedType, etc.)
   46 CommandLine (12 Parsing, 10 CommandFactory, 6 Internal, etc.)
   16 ServiceContainer.cs
    6 JasperFxOptions.cs
   10 misc (Resources, Environment, Descriptors, etc.)

JasperFx.Events — 134 warnings
   30 Projections/EventProjectionApplication.cs
   60 Aggregation/* (JasperFxAggregationProjectionBase, AggregateApplication.*, CreateMethodCollection, AggregateVersioning, ApplyMethodCollection)
   12 Internals + IEventRegistry
   16 Daemon, CommandLine, StreamAction, Tags, misc

These are the inputs for the rest of the AOT pillar:

  - The CommandLine slice will be addressed in the follow-up audit
    (#213 sub-item — "Audit reflective discovery in
    JasperFx.CommandLine for IJasperFxCommand").

  - The AOT-clean smoke-test consumer project (next pillar sub-item) will
    pin the build clean once each slice has been annotated or migrated.

  - The Reflection / IoC / Aggregation slices want follow-up issues filed
    against the pillar to track per-area annotation work.
@jeremydmiller jeremydmiller merged commit 0a2527a into main May 12, 2026
1 check passed
thechucklingatom pushed a commit to thechucklingatom/jasperfx that referenced this pull request May 19, 2026
Second deliverable on the AOT compliance pillar (JasperFx#213). Walks the
JasperFx.CommandLine subsystem and either annotates each reflective entry
point with [RequiresUnreferencedCode] / [RequiresDynamicCode] or suppresses
analyzer warnings with a [UnconditionalSuppressMessage] that names the
already-annotated entry point.

Public surfaces annotated

  ICommandCreator.CreateCommand / CreateModel
  ActivatorCommandCreator        — Activator.CreateInstance(Type)
  DependencyInjectionCommandCreator — ActivatorUtilities + GetProperties
  ICommandFactory               — BuildRun / RegisterCommands / BuildAllCommands / ApplyExtensions
  CommandFactory                — RegisterCommand[s], BuildRun, BuildAllCommands,
                                  HelpRun, Build, ApplyExtensions, RegisterCommandsFromExtensionAssemblies
  CommandExecutor               — ExecuteCommand[Async]<T>, Execute / ExecuteAsync
  CommandLineHostingExtensions  — RunJasperFxCommands*, ApplyJasperFxExtensions, ApplyFactoryDefaults
  OaktonShims                   — ApplyOaktonExtensions, RunOaktonCommands (legacy aliases)
  InputParser                   — GetHandlers / BuildHandler
  UsageGraph(Type) + BuildInput

Suppressed at the call site (justified by entry-point annotations)

  CommandFactory.TryRegisterFromGeneratedManifest — emits via JasperFx.SourceGenerator
  CommandExecutor.execute                         — Spectre WriteException only on error path
  EnumerableArgument.Handle / EnumerableFlag.Handle — CloseAndBuildAs reachable only
                                                      from annotated entry points
  ArrayConversion.ConverterFor                    — Array.CreateInstance via Conversions
  StringConverterProvider.ConverterFor            — Type.GetConstructor via Conversions
  DescribeCommand.ReferencedAssemblies.WriteToConsole — diagnostic-only
  JasperFxCommand<T> / JasperFxAsyncCommand<T> constructors —
    UsageGraph reads T's members which are preserved via the annotated
    RegisterCommand entry point

Source-generated path preserved

  CommandFactory.TryRegisterFromGeneratedManifest is the AOT-clean fast path.
  Apps that include JasperFx.SourceGenerator emit the
  JasperFx.Generated.DiscoveredCommands manifest as ordinary source, which
  survives trimming naturally. The reflective fallback (RegisterCommands /
  RegisterCommandsFromExtensionAssemblies) is exactly what the annotations
  warn AOT consumers about.

Effect on the IL warning punch list

  Before (after JasperFx#213 flag-flip in PR JasperFx#247):
    JasperFx total per TFM: 236 warnings, of which CommandLine slice: 46
  After this PR:
    JasperFx total per TFM: 188 warnings, of which CommandLine slice: 0

  Remaining warnings sit in Core/Reflection (128), Core/IoC (60),
  CodeGeneration/Services (44), ServiceContainer.cs (32), and a long
  tail of smaller areas — each is a follow-up issue against JasperFx#213.

CommandLineTests (280), CoreTests (407), CodegenTests (366) all pass on
net9.0 + net10.0. Runtime behavior is unchanged; the annotations are
analyzer-only.
thechucklingatom pushed a commit to thechucklingatom/jasperfx that referenced this pull request May 19, 2026
Carries the AOT pillar Tier 1 work (JasperFx#213) that landed in JasperFx#247
(IsAotCompatible=true on JasperFx + JasperFx.Events) and JasperFx#250 (CommandLine
reflective surface annotated + AOT-clean smoke test in CI). Downstream
consumers — Weasel 9 (alpha.8 → alpha.11 refresh queued via weasel#273),
Polecat 4 (alpha.8 today), Marten 9 — can pick this up to get the AOT
analyzer flag and the precise CommandLine punch list.

Other packages (JasperFx.RuntimeCompiler, JasperFx.SourceGeneration,
JasperFx.Events.SourceGenerator) keep their current alpha — nothing
changed in those projects this cycle. NugetPush is `SkipDuplicate` so
the re-published artifacts at their existing versions are no-ops.
thechucklingatom pushed a commit to thechucklingatom/jasperfx that referenced this pull request May 19, 2026
Final AOT-pillar cleanup pass for JasperFx (JasperFx#213). After PRs
JasperFx#256JasperFx#259 closed the four largest slices (ServiceContainer,
CodeGeneration/Services, Core/IoC, Core/Reflection), 74 warnings per
TFM remained across the long tail. This PR brings the JasperFx project
to **0 IL warnings** with `IsAotCompatible=true` enabled.

Annotated reflective entry points

  AssemblyFinder.FindAssemblies (3 overloads)   — [RUC]
  IJasperFxAssemblyLoadContext + impl            — [RUC]
  AssemblyTypes(Assembly)                        — [RUC]
  TypeRepository.ForAssembly / FindTypes (3x)    — [RUC]
  TypeQuery.Find(IEnumerable<Assembly>)          — [RUC]
  AssemblyScanner.Start + assembly-scan APIs     — [RUC] (matches
                                                   IAssemblyScanner)
  IAssemblyScanner.AssembliesFrom*               — [RUC] on interface
  CommandLineHostingExtensions.ApplyJasperFx*    — already RUC; cascades
  JasperFxOptions.HasReferenceToJasperFxTool     — [RUC]
  JasperFxOptions.DetermineCallingAssembly       — [RUC]
  JasperFxOptions.establishApplicationAssembly   — [RUC]
  JasperFxOptions.ReadHostEnvironment            — [RUC]
  JasperFxServiceCollectionExtensions.AddJasperFx + CritterStackDefaults
                                                  — [RUC]
  EnvironmentCheckExtensions (5 overloads)       — [RUC]
  SnapshotGate.Read / SnapshotGate.Write         — [RUC] + [RDC]
                                                   (STJ JsonSerializer)
  ISystemPart.WriteToConsole                     — [RUC] on interface
  DescribeCommand.Execute                        — suppress + #pragma
                                                   on async-state-machine
                                                   WriteToConsole call
  CodeGeneration/Frames/MethodCall(Type,string)  — [RUC] + [DAM(PublicMethods)]
  CodeGeneration/Frames/MethodCall.correctedReturnType — suppress IL2067
                                                   (well-known Task types)
  CodeGeneration/Frames/MethodCall.returnsValueTask — suppress IL2072
  CodeGeneration/GeneratedAssembly.AddType       — [DAM(PublicCtors|PublicMethods|NonPublicMethods)]
  CodeGeneration/GeneratedAssembly.AttachAssembly — [RUC]
  CodeGeneration/GeneratedType.CompiledType property — [DAM(PublicCtors)]
  CodeGeneration/GeneratedType.InheritsFrom<T>/<Type> — [DAM(PublicCtors|Methods)]
  CodeGeneration/GeneratedType.Implements<T>/(Type) — [DAM(PublicMethods)]
  CodeGeneration/GeneratedType.FindType + ApplySetterValues — [RUC]/suppress
  CodeGeneration/Model/Setter.SetInitialValue    — [RUC]
  CodeGeneration/Model/Variable.VariablesForProperties<T> — [DAM(PublicProperties)]
  CodeGeneration/Model/Variable.DefaultArgName   — suppress (cosmetic)
  CodeGeneration/Expressions/LambdaDefinition.Compile<TFunc> — [RUC]
  ServiceCollectionServerVariableSource.Matches  — suppress (IVariableSource
                                                   contract doesn't carry DAM)
  CodeGeneration/CodeGenerationExtensions.BuildExportedTypeIndex — suppress
  CodeGeneration/Services findFamily             — re-applied IL2067 suppression
                                                   (was lost in JasperFx#256 + JasperFx#257 merge)
  ServiceContainer.CouldResolve(Type)            — [DAM(PublicCtors)]
  ServiceContainer.findFamily                    — re-applied IL2067 suppression
                                                   (was lost in PR JasperFx#256 + JasperFx#257
                                                   merge resolution)
  Descriptors/OptionsDescription                 — [RUC] on ctor / For() / readProperties
  Descriptors/DatabaseDescriptor ctors           — [RUC] (inherits OptionsDescription)
  CommandLine/Descriptions/ConfigurationPreview.WriteToConsole — [RUC]
  CommandLine/Descriptions/DescribeCommand.WriteToConsole (×2 overrides) — [RUC]
  CommandLine/CommandFactory.IsJasperFxCommandType — [DAM(Interfaces)]
  CommandLine/CommandFactory.TryRegisterFromGeneratedManifest — IL2072 suppress added
  Resources/ResourcesCommand.ExecuteOnEach        — suppress IL3050
                                                   (Spectre WriteException
                                                   on error-display path)
  JasperFxAssemblyAttribute ctor                 — [DAM(PublicCtors|NonPublicCtors)]

Effect on the punch list

  Before:  JasperFx total per TFM  74 warnings
  After:   JasperFx total per TFM   0 warnings

  Cumulative since JasperFx#213 flag-flip (PR JasperFx#247):
    236 (initial fallout) → 0  (all addressed)

Note on JasperFx.Events

  The propagation of new annotations into the JasperFx.Events compilation
  surfaces ~246 warnings per TFM that aren't addressed here. That deserves
  its own focused PR + likely an issue under JasperFx#213.

Verification

  CoreTests       407/407 pass on net9.0 + net10.0
  CommandLineTests 280/280 pass on net9.0 + net10.0
  CodegenTests    366/366 pass on net9.0 + net10.0
  SmokeTestAot    build clean, exits 0

Closes (most) the AOT pillar JasperFx#213 for JasperFx itself. Events follow-up
deferred to a separate PR.
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.

1 participant