Skip to content

weasel#263: Add Weasel.Core.AotSmoke + per-provider IsAotCompatible audit#283

Merged
jeremydmiller merged 1 commit into
masterfrom
chore/263-aot-smoke-and-provider-audit
May 18, 2026
Merged

weasel#263: Add Weasel.Core.AotSmoke + per-provider IsAotCompatible audit#283
jeremydmiller merged 1 commit into
masterfrom
chore/263-aot-smoke-and-provider-audit

Conversation

@jeremydmiller
Copy link
Copy Markdown
Member

Ticks off two boxes on the Weasel 9.0 master tracker (#263):

  • The missing AOT smoke-test consumer project (parallel to JasperFx.AotSmoke in jasperfx).
  • The per-provider AOT-flag audit across Weasel.Postgresql / Weasel.SqlServer / Weasel.Oracle / Weasel.MySql / Weasel.Sqlite / Weasel.EntityFrameworkCore.

Part 1 — Weasel.Core.AotSmoke

New console project src/Weasel.Core.AotSmoke/ modelled on src/JasperFx.AotSmoke/ in jasperfx (commit d4077d8):

  • Microsoft.NET.Sdk console Exe, IsAotCompatible=true, TrimMode=full
  • WarningsAsErrors=IL2026;IL2046;IL2055;IL2065;IL2067;IL2070;IL2072;IL2075;IL2090;IL2091;IL2111;IL3050;IL3051 (mirroring jasperfx)
  • ProjectReference to Weasel.Core only — no provider deps, per the chip

Program.cs exercises the #270 consolidation surface: DbObjectName, the cross-provider enums, ForeignKeyBase.Parse / LinkColumns / Equals, TableBase<TColumn, TIndex, TForeignKey> (via a SmokeTable subclass that overrides every abstract), and IDdlSyntaxStrategy (via a SmokeSyntax implementation). Wired into Weasel.slnx so CI workflows pick it up.

Part 1.5 — Fix two pre-existing Weasel.Core warnings the smoke test surfaced

The smoke project's IsAotCompatible build immediately flagged two defects from PR #272 that the original IL3050/IL2075 cleanup hadn't quite landed correctly:

  • IL3051 in AssertCommand.cs — the [RequiresDynamicCode] override didn't match the unannotated base (JasperFxAsyncCommand<T>.Execute). Removed [RequiresDynamicCode] and kept the [UnconditionalSuppressMessage] for IL3050, which actually silences the underlying warning.
  • IL2098 in CommandBuilderBase.cs[DynamicallyAccessedMembers] on an object parameter is invalid (the attribute only works on Type / string params). Removed the attribute; updated xmldoc to point at the [RequiresUnreferencedCode] already on the method as the actual caller-contract.

This is direct evidence the smoke test works as designed.

Part 2 — Per-provider audit table

Provider IsAotCompatible Notes
Weasel.Postgresql true + 3 wrapper annotations: ICommandBuilder.AddParameters(object) marked [RequiresUnreferencedCode] to match the base; BatchBuilder.AddParameters(object) likewise + IL2075 suppression at the GetType().GetProperties() call site; PostgresqlProvider.determineParameterType suppresses IL2070 at the typeInfo.ImplementedInterfaces lookup (cold-path IEnumerable<T> detection), GetNullableType marked [RequiresDynamicCode] for the Type.MakeGenericType(Nullable<>) call, AddTimespanTypes + CustomizableWhereFragment.Apply suppress the resulting cascade with Justifications. Pre-register types via storeMappings / RegisterMapping to avoid these paths under AOT.
Weasel.SqlServer true + 2 wrapper annotations: ICommandBuilder.AddParameters(object) and BatchBuilder.AddParameters(object) — same [RequiresUnreferencedCode] pattern as PG.
Weasel.Oracle true Clean out of the box.
Weasel.MySql true Clean out of the box.
Weasel.Sqlite true Clean out of the box.
Weasel.EntityFrameworkCore true + 4 wrapper suppressions on EF Core's reflective surfaces (FindEntityType, AddTransient<TImpl>, GetType().GetProperty by name). EF Core upstream is not AOT-ready (dotnet/efcore#29761); consumers of Weasel.EntityFrameworkCore targeting AOT inherit that limitation. Justifications point at the upstream issue.

Test plan

  • dotnet build Weasel.slnx — 0 warnings, 0 errors
  • Smoke executable runs and exits cleanly under net10.0: Weasel.Core AOT smoke OK — exercised DbObjectName, ForeignKeyBase.Parse, TableBase, IDdlSyntaxStrategy.
  • Smoke catches regressions: empirically proven — the smoke project's first build surfaced IL3051 + IL2098 in Weasel.Core (pre-existing defects from Resolve #261, #265, #266 — Core.CascadeAction overloads + AOT annotations #272 that the chip-listed sanity criterion was designed to detect). Both fixed in Part 1.5.
  • Behavioural test runs: Weasel.Core 6/6, Weasel.Postgresql 634/640 (6 pre-existing skips), Weasel.Sqlite 360/361 (1 pre-existing timezone-boundary flake), Weasel.Core.Tests 6/6
  • Weasel.EntityFrameworkCore.Tests shows 17 failures but these are pre-existing on bare master (confirmed via git stash toggle) — require SQL Server connectivity not available locally

References #263, JasperFx/jasperfx#213.

🤖 Generated with Claude Code

…udit

Part 1 — Weasel.Core.AotSmoke

New console project src/Weasel.Core.AotSmoke/ that mirrors the
src/JasperFx.AotSmoke/ pattern (jasperfx commit d4077d8):

  - Microsoft.NET.Sdk console Exe, IsAotCompatible=true, TrimMode=full
  - WarningsAsErrors=IL2026;IL2046;IL2055;IL2065;IL2067;IL2070;IL2072;
    IL2075;IL2090;IL2091;IL2111;IL3050;IL3051 (mirroring jasperfx)
  - ProjectReference to Weasel.Core only (no provider deps — that's
    intentionally separate, per the chip)

Program.cs touches a representative cross-section of Weasel.Core's
post-#270 consolidation surface:

  - DbObjectName(schema, name) + .QualifiedName
  - Cross-provider enums: CascadeAction, EnumStorage, CreationStyle,
    SchemaPatchDifference, SqlFormatting, BulkInsertMode, AutoCreate
  - ForeignKeyBase.Parse + LinkColumns + structural Equals (the #270
    step 4 consolidation outputs)
  - TableBase<TColumn, TIndex, TForeignKey>: AddColumn,
    AddPrimaryKeyColumn, HasColumn, ColumnFor, AddForeignKey,
    PrimaryKeyName (via DefaultPrimaryKeyName hook), RemoveColumn,
    IgnoreIndex (#270 step 9)
  - IDdlSyntaxStrategy: implement + call WriteDropTable +
    WriteCreateTableHeader + the property surface (#270 step 8)

Minimal SmokeColumn / SmokeIndex / SmokeForeignKey / SmokeTable /
SmokeMigrator / SmokeSyntax stubs implement just enough of each
abstract base to instantiate it from this consumer project. Bodies
that aren't exercised throw — the smoke test only cares whether the
surface compiles cleanly under IsAotCompatible=true + TrimMode=full.

Wired into Weasel.slnx so CI workflows (which run plain dotnet build)
pick it up automatically. No CI-yml changes needed.

Part 1.5 — Fix two pre-existing IL warnings in Weasel.Core

The smoke project's IsAotCompatible build immediately surfaced two
defects from PR #272 that the original IL3050/IL2075 cleanup hadn't
quite landed correctly:

  IL3051 in AssertCommand.cs:31 — the [RequiresDynamicCode] override
  didn't match the unannotated base (JasperFxAsyncCommand<T>.Execute).
  Removed [RequiresDynamicCode] and kept the [UnconditionalSuppressMessage]
  for IL3050, which actually silences the underlying warning.

  IL2098 in CommandBuilderBase.cs:291 — [DynamicallyAccessedMembers]
  on an `object` parameter is invalid (the attribute only works on
  Type/string parameters). Removed the attribute and updated xmldoc
  to point at the [RequiresUnreferencedCode] already on the method
  as the actual caller-contract.

Part 2 — Per-provider IsAotCompatible audit

| Provider | IsAotCompatible | Notes |
|---|---|---|
| Weasel.Postgresql | true | + 3 wrapper annotations: ICommandBuilder.AddParameters(object) marked [RequiresUnreferencedCode] to match the base; BatchBuilder.AddParameters(object) likewise + IL2075 suppression at the GetType().GetProperties() call site; PostgresqlProvider.determineParameterType suppresses IL2070 at the typeInfo.ImplementedInterfaces lookup (cold-path IEnumerable<T> detection), GetNullableType marked [RequiresDynamicCode] for the Type.MakeGenericType(Nullable<>) call, AddTimespanTypes + CustomizableWhereFragment.Apply suppress the resulting cascade with Justifications. Pre-register types via storeMappings / RegisterMapping to avoid these paths under AOT. |
| Weasel.SqlServer | true | + 2 wrapper annotations: ICommandBuilder.AddParameters(object) and BatchBuilder.AddParameters(object) — same RUC pattern as PG. |
| Weasel.Oracle | true | Clean out of the box. |
| Weasel.MySql | true | Clean out of the box. |
| Weasel.Sqlite | true | Clean out of the box. |
| Weasel.EntityFrameworkCore | true | + 4 wrapper suppressions on EF Core's reflective surfaces (FindEntityType, AddTransient<TImpl>, GetType().GetProperty by name). EF Core upstream is not AOT-ready (dotnet/efcore#29761); consumers of Weasel.EntityFrameworkCore targeting AOT inherit that limitation. Justifications point at the upstream issue. |

Acceptance criteria:

- dotnet build clean on the entire solution (Weasel.slnx); the smoke
  project's WarningsAsErrors list is fully satisfied.
- The smoke executable exits cleanly under net10.0:
  "Weasel.Core AOT smoke OK — exercised DbObjectName, ForeignKeyBase.Parse,
   TableBase, IDdlSyntaxStrategy."
- Per-provider audit table documented above.
- The "smoke test catches regressions" sanity criterion: empirically
  proven by the two pre-existing Weasel.Core IL warnings (IL3051 +
  IL2098) that the smoke build immediately surfaced and are now
  fixed in Part 1.5.

Behavioural impact: none. All annotations are AOT/trim diagnostics
that affect compile-time analyzer output, not runtime behaviour.
Test suites that ran:

  - Weasel.Core: 6/6
  - Weasel.Postgresql: 634/640 (6 pre-existing skips)
  - Weasel.Sqlite: 360/361 (1 pre-existing timezone-boundary flake)
  - Weasel.EntityFrameworkCore: 18/35 (17 pre-existing failures
    against bare master — confirmed via `git stash`; require SQL
    Server connectivity not available locally)

References weasel#263, JasperFx/jasperfx#213.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@jeremydmiller jeremydmiller merged commit 5844c9f into master May 18, 2026
21 checks passed
@jeremydmiller jeremydmiller deleted the chore/263-aot-smoke-and-provider-audit branch May 18, 2026 10:59
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