Skip to content

[release/13.4] Freeze Aspire.TypeSystem AssemblyVersion at 13.4.5.0 to fix cross-ALC codegen binding#18160

Merged
davidfowl merged 1 commit into
release/13.4from
sebastienros/typesystem-alc-pinning-regression
Jun 17, 2026
Merged

[release/13.4] Freeze Aspire.TypeSystem AssemblyVersion at 13.4.5.0 to fix cross-ALC codegen binding#18160
davidfowl merged 1 commit into
release/13.4from
sebastienros/typesystem-alc-pinning-regression

Conversation

@sebastienros

@sebastienros sebastienros commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

Problem

Polyglot AppHost code generation (TypeScript/Python/Java/Go/Rust) silently fails with No code generator found for language: <lang> when the installed Aspire CLI and the AppHost's configured SDK skew in version (e.g. an older CLI running a newer SDK, or a current CLI running an older stable SDK).

Root cause

The CLI's bundled apphost server (Aspire.Hosting.RemoteHost, shipped as the single-file aspire-managed executable) loads Aspire.TypeSystem into its default AssemblyLoadContext and IntegrationLoadContext deliberately force-shares it from there, so the cross-ALC contracts (ICodeGenerator, ILanguageSupport, AtsContext) keep a single type identity across the ALC boundary.

The SDK-side codegen assemblies (Aspire.Hosting.CodeGeneration.*) are strong-named (StrongNameKeyId=Open) and carry a strong-named reference to Aspire.TypeSystem. The CLR satisfies a strong-named reference only when the loaded copy's AssemblyVersion is >= the requested version. Because AssemblyVersion floated with the build (MAJOR.MINOR.PATCH), the bundled copy and the codegen reference diverged whenever the CLI and SDK were built at different times → the bind failed → Assembly.GetTypes() threw ReflectionTypeLoadException → every generator was silently dropped (#18110, #17910).

This affects all polyglot languages and the ATS capability-scan path, not just TypeScript. The Aspire.TypeSystem source surface itself is unchanged between release/13.4 and main — it is purely the strong-name version bump that breaks the bind.

Fix

Freeze the strong-name AssemblyVersion of Aspire.TypeSystem at the fixed constant 13.4.4.0, decoupled from the build:

  • 13.4.4.0 is the version of the 13.4.4 servicing release that introduces the freeze, and is >= 13.4.3.0 (the latest shipped stable), so a current CLI binds against any already-shipped stable app's codegen reference — the common, must-work backward-compat direction.
  • Merged forward to main so every later stable and servicing release (13.4.4, 13.5, ...) bundles the same value; post-freeze CLI/SDK pairs then match exactly and no skew matters. On release/13.4 the product version is already 13.4.4, so this is a no-op for that build and only constrains future minors.
  • Only AssemblyVersion is frozen; FileVersion, InformationalVersion, and the NuGet package version stay build-derived, so diagnostics keep real build identities. Aspire.TypeSystem is consumed only via ProjectReference (no PackageReference consumers), so the frozen assembly version is not a package contract anyone binds to by exact version, and CP0003 package-baseline validation still passes (13.4.4.0 >= baseline).

Residual cases (routed to diagnostics, not silent)

Two narrow skews can't be fixed by any freeze value and are surfaced as an actionable "run aspire update" message by the #18125 diagnostics:

  1. An already-shipped old CLI (real, lower bundled version) running post-freeze codegen that references 13.4.4.0.
  2. A pre-freeze 13.5.0 preview app whose codegen still references a real 13.5.0.0 (> 13.4.4.0); preview-channel skew is outside the supported stable matrix and is superseded by post-freeze builds.

Back-compat guard

Because binding now succeeds on version alone, that safety only holds if the shared contract stays strictly additive. AtsSharedContractSurfaceTests snapshots the shared-contract surface (embedded baseline) and fails on any removal/signature change, forcing a deliberate decision: additive (no bump) vs breaking (bump AssemblyVersion).

Validation

  • Aspire.Hosting.RemoteHost.Tests: 451/451 passed on the release/13.4 base (includes the new contract-surface guard).
  • dotnet pack src/Aspire.TypeSystem: succeeds with no CP0003 override.
  • Faithful strong-named A/B bind repro confirms BEFORE → ReflectionTypeLoadException (generators dropped), AFTER → generator discovered.

Targets release/13.4 for the 13.4.4 servicing release. Relates to #18110, #17910; complementary to the #18125 diagnostics.

Copilot AI review requested due to automatic review settings June 12, 2026 15:27
@github-actions

github-actions Bot commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

🚀 Dogfood this PR with:

⚠️ WARNING: Do not do this without first carefully reviewing the code of this PR to satisfy yourself it is safe.

curl -fsSL https://raw.githubusercontent.com/microsoft/aspire/main/eng/scripts/get-aspire-cli-pr.sh | bash -s -- 18160

Or

  • Run remotely in PowerShell:
iex "& { $(irm https://raw.githubusercontent.com/microsoft/aspire/main/eng/scripts/get-aspire-cli-pr.ps1) } 18160"

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

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 fixes a critical issue where polyglot (TypeScript/Python/Java/Go/Rust) AppHost code generation silently fails when the installed Aspire CLI is older than the AppHost's configured SDK within the same major version (e.g., 13.4.3 CLI + 13.5.0 SDK). The root cause was that the strong-named AssemblyVersion floated with MAJOR.MINOR.PATCH, preventing the older bundled Aspire.TypeSystem from satisfying newer codegen assemblies' strong-named references.

Changes:

  • Pins Aspire.TypeSystem's AssemblyVersion to $(MajorVersion).0.0.0 so that any CLI/SDK combination within the same major binds successfully, while preserving real build identities in FileVersion and InformationalVersion.
  • Adds explanatory comments in IntegrationLoadContext and AssemblyLoader documenting why the version pin makes the shared-assembly short-circuit and mismatch check safe.
  • Introduces AtsSharedContractSurfaceTests with an embedded baseline snapshot to guard against future breaking changes to the public surface that could reintroduce the binding failure.

Reviewed changes

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

Show a summary per file
File Description
src/Aspire.TypeSystem/Aspire.TypeSystem.csproj Core fix: pins AssemblyVersion to MAJOR.0.0.0 with thorough rationale comment
src/Aspire.Hosting.RemoteHost/IntegrationLoadContext.cs Documents why the SharedAssemblyName short-circuit is safe under the pinned version
src/Aspire.Hosting.RemoteHost/AssemblyLoader.cs Restructures WarnIfSharedAssemblyMismatch docs to explain post-pin semantics (cross-major only warning, same-version/differing-MVID is benign)
tests/Aspire.Hosting.RemoteHost.Tests/AtsSharedContractSurfaceTests.cs New back-compat guard test comparing assembly public surface against embedded baseline
tests/Aspire.Hosting.RemoteHost.Tests/Aspire.Hosting.RemoteHost.Tests.csproj Adds embedded resource and Aspire.TypeSystem project reference for the new test
tests/Aspire.Hosting.RemoteHost.Tests/Snapshots/AtsSharedContractSurface.txt Frozen public API surface baseline for Aspire.TypeSystem

@sebastienros sebastienros marked this pull request as draft June 12, 2026 15:33
Copilot AI review requested due to automatic review settings June 12, 2026 15:54
@sebastienros sebastienros changed the title Pin Aspire.TypeSystem AssemblyVersion to stabilize cross-ALC contract binding Freeze Aspire.TypeSystem AssemblyVersion to stabilize cross-ALC contract binding Jun 12, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated 1 comment.

Comment thread src/Aspire.Hosting.RemoteHost/AssemblyLoader.cs Outdated
Copilot AI review requested due to automatic review settings June 12, 2026 16:15

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated 1 comment.

Comment thread src/Aspire.Hosting.RemoteHost/AssemblyLoader.cs Outdated
Copilot AI review requested due to automatic review settings June 12, 2026 16:28

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 31 out of 31 changed files in this pull request and generated no new comments.

Copilot AI review requested due to automatic review settings June 12, 2026 17:04

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 31 out of 31 changed files in this pull request and generated 1 comment.

Comment thread tests/Aspire.Hosting.RemoteHost.Tests/AtsSharedContractSurfaceTests.cs Outdated
Copilot AI review requested due to automatic review settings June 12, 2026 17:24
@sebastienros

sebastienros commented Jun 12, 2026

Copy link
Copy Markdown
Contributor Author

PR Testing Report

PR Information

Artifact Version Verification

  • Expected Commit (PR head): 37ba357
  • Installed CLI version: 13.4.4-pr.18160.g37ba3575
  • Status: ✅ Verified (short SHA g37ba3575 matches PR head)

Changes Analyzed

Files Changed

  • src/Aspire.TypeSystem/Aspire.TypeSystem.csproj — froze <AssemblyVersion>13.4.4.0</AssemblyVersion> (the only production change). No DisablePackageBaselineValidation13.4.4.0 >= 13.4.0 baseline, so CP0003 passes naturally.
  • src/Aspire.Hosting.RemoteHost/IntegrationLoadContext.cs — comment-only (brief pointer to the csproj rationale on the shared-from-bundle short-circuit).
  • src/Aspire.Hosting.RemoteHost/AssemblyLoader.cs — comment-only (WarnIfSharedAssemblyMismatch; warns only when bundled < probed).
  • tests/Aspire.Hosting.RemoteHost.Tests/SharedContractSurface.cs / SharedContractSurfaceTests.cs / AtsSharedContractSurfaceTests.cs / Snapshots/AtsSharedContractSurface.txt — contract-freeze guard. The guard now also renders declared interfaces + base type + static modifiers so an : ICodeGenerator removal or an instance→static flip also trips it.

Change Categories

  • CLI changes detected (no behavioral CLI code; only ATS assembly-version metadata + RemoteHost comments)
  • Hosting changes (Aspire.TypeSystem build metadata; RemoteHost comment-only)
  • Dashboard changes
  • CI infrastructure changes
  • VS Code extension changes
  • Test changes (contract-freeze guard)

Frozen-version proof (the heart of the fix)

Extracted from the dogfood hive (Aspire.TypeSystem.13.4.4-pr.18160.g37ba3575.nupkg and Aspire.Hosting.CodeGeneration.TypeScript.*.nupkg) and read via AssemblyName / PEReader metadata:

Aspire.TypeSystem.dll AssemblyVersion = 13.4.4.0
CodeGeneration.TypeScript references Aspire.TypeSystem, Version=13.4.4.0

The package version still floats (13.4.4-pr.18160.g37ba3575); only the AssemblyVersion is frozen at 13.4.4.0. Because 13.4.4.0 >= 13.4.3.0 (latest shipped stable), a CLI bundling this ATS satisfies the strong-named reference carried by codegen assemblies from current and older stable SDKs — which is the bind that the regression broke.

Test Scenarios Executed

Scenario 1: Install + version match

Objective: Install the PR CLI and confirm it reports the PR head commit.
Coverage Type: Happy path
Status: ✅ Passed

Steps:

  1. get-aspire-cli-pr.sh 18160 --install-path <tmp> --skip-path --skip-extension
  2. <cli> --version

Evidence: version 13.4.4-pr.18160.g37ba3575; both built-nugets and cli-native-archives-osx-arm64 artifacts downloaded.


Scenario 2: TypeScript AppHost codegen (regression check)

Objective: Verify TypeScript polyglot code generation works (the exact path that failed in the regression).
Coverage Type: Happy path (regression guard)
Status: ✅ Passed

Steps:

  1. <cli> init --language typescript --non-interactive (fresh temp dir; npm deps installed by init).
  2. <cli> add Aspire.Hosting.Redis --non-interactiveAspire.Hosting.Redis::13.4.4-pr.18160.g37ba3575 added.
  3. Removed .aspire/modules, then <cli> restore --apphost <tmp>/apphost.mts --non-interactive.

Evidence (ts-restore.log):

  • ✅ SDK code restored successfully for apphost.mts. (exit 0)
  • Generated .aspire/modules/: aspire.mts (2.6 MB), base.mts, transport.mts, .codegen-hash
  • Generated aspire.mts contains the Redis surface (1366 addRedis/RedisResource references).
  • No No code generator found for language: TypeScript; no ReflectionTypeLoadException / FileLoadException.

Scenario 3: Python AppHost codegen (regression check)

Objective: Verify a second polyglot language (Python) codegen path works.
Coverage Type: Happy path (regression guard)
Status: ✅ Passed

Steps:

  1. Staged tests/PolyglotAppHosts/Aspire.Hosting.Redis/Python into <tmp>/py with an aspire.config.json (language: python, experimentalPolyglot:python feature, SDK 13.4.4-pr.18160.g37ba3575) and a NuGet.config pointing at the PR hive. (aspire init exposes only csharp/typescript; Python polyglot is experimental and config-driven.)
  2. <cli> restore --apphost <tmp>/py/apphost.py --non-interactive.

Evidence (py-restore.log):

  • ✅ SDK code restored successfully for apphost.py. (exit 0)
  • Generated .aspire/modules/: aspire_app.py (530 KB), pyproject.toml, .codegen-hash
  • Generated aspire_app.py contains the Redis surface (43 add_redis/redis references).
  • No No code generator found; no loader/bind exception. (An unrelated pylock.apphost.toml not-found notice is the Python dep-lock step, not codegen — codegen reported success after it.)

Scenario 4: Package build (CP0003) ships without any override

Objective: Confirm the 13.4.4.0 freeze does not trip package baseline validation.
Coverage Type: Boundary / build validation
Status: ✅ Passed

Key delta vs the earlier 1.0.0.0 sentinel: the old value was < 13.4.0 baseline and required DisablePackageBaselineValidation=true. With 13.4.4.0 >= 13.4.0, CP0003 passes naturally and the override has been removed.

Evidence (CI run 27453745514, head 37ba3575):

  • Tests / Build packages / Build packages → conclusion success (no DisablePackageBaselineValidation).
  • Package version still floats (pr.18160.g37ba3575); only AssemblyVersion is frozen.

CI corroboration: all five polyglot languages green on head 37ba3575 (run 27453745514)

Beyond the two local runs above, the full polyglot codegen matrix is green on the PR head:

  • Polyglot SDK Validation: TypeScript (Node 24.x), Python, Java, Go, Rust → all success
  • Hosting.CodeGeneration.{TypeScript, Python, Go, Java, Rust} (ubuntu + windows) → all success
  • Cli.EndToEnd-TypeScriptCodegenValidationTests + Cli.EndToEnd-JavaCodegenValidationTestssuccess

This confirms the fix holds across every codegen language that references Aspire.TypeSystem, not just the two exercised locally.

Scope note: what these scenarios do and do NOT cover

A dogfood install is a single matched CLI/SDK version, so it cannot reproduce the genuine old-CLI + newer-SDK strong-name skew that is the regression. Scenarios 2–3 are a happy-path regression check: they prove the 13.4.4.0 AssemblyVersion freeze does not break ATS loading / cross-ALC type identity when versions match (a wrong freeze value would break codegen even in the matched case), and the frozen-version proof above shows the codegen assemblies now carry a 13.4.4.0 reference that an equal-or-older-stable bundled copy satisfies. The actual skew bind (BEFORE = ReflectionTypeLoadException → 0 generators; AFTER = generator discovered) was proven earlier with real strong-named binaries in the A/B repro matrix, and is locked in by the AtsSharedContractSurface contract-freeze guard.

Complementarity with #18125

The two PRs fully complement each other:

Summary

Scenario Status Notes
1. Install + version match ✅ Passed 13.4.4-pr.18160.g37ba3575 matches head
2. TypeScript codegen ✅ Passed aspire.mts 2.6 MB, 1366 Redis refs, no cryptic error
3. Python codegen ✅ Passed aspire_app.py 530 KB, 43 Redis refs, no cryptic error
4. Package build (CP0003) ✅ Passed No DisablePackageBaselineValidation needed (13.4.4.0 >= 13.4.0)
CI polyglot matrix (TS/Py/Java/Go/Rust) ✅ Passed run 27453745514, all codegen suites green

Overall Result

✅ PR VERIFIED

Notes

  • Frozen AssemblyVersion = 13.4.4.0 is a no-op on release/13.4 (product is already 13.4.4) and only constrains 13.5+; merged forward to main it keeps every future stable/servicing bundle on the sentinel.
  • Skew (old/pre-freeze CLI + newer SDK) is intentionally not dogfood-reproducible; that path relies on the prior binary A/B repro + the contract-freeze guard + Surface actionable diagnostic when TypeScript codegen generator is dropped by load failure #18125 diagnostics.
  • PR is a draft — this is test-and-report only; no approve/merge performed.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 31 out of 31 changed files in this pull request and generated no new comments.

Comment thread src/Aspire.TypeSystem/Aspire.TypeSystem.csproj Outdated
Comment thread src/Aspire.TypeSystem/Aspire.TypeSystem.csproj Outdated
@github-actions

Copy link
Copy Markdown
Contributor

Retrying the failed CI jobs for this pull request from the CI run attempt. The rerun is being tracked in the rerun attempt.

Copilot AI review requested due to automatic review settings June 13, 2026 01:40
@sebastienros sebastienros force-pushed the sebastienros/typesystem-alc-pinning-regression branch from a68ad08 to 39c789d Compare June 13, 2026 01:40
@sebastienros sebastienros changed the base branch from main to release/13.4 June 13, 2026 01:40
@sebastienros sebastienros changed the title Freeze Aspire.TypeSystem AssemblyVersion to stabilize cross-ALC contract binding Freeze Aspire.TypeSystem AssemblyVersion at 13.4.4.0 to fix cross-ALC codegen binding Jun 13, 2026
This was referenced Jun 26, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

4 participants