Skip to content

Move off legacy target frameworks (netstandard2.0 / net472) so shared contracts can live in Fallout.Core #441

Description

@ChrisonSimtian

Description

The plugin-SDK / de-statification work (milestone #6 foundation → #7 SDK) needs stable abstractions — Configure<T>, an AbsolutePath abstraction, the tool-execution contracts, eventually a lifted IFalloutBuild — to live in the innermost Fallout.Core (netstandard2.1;net10.0). Today a netstandard2.0 "floor" blocks that: an ns2.0 project can't reference ns2.1 Core, so types that ns2.0 assemblies consume are stranded outside Core. We want to deliberately move the codebase toward .NET (net10) only and shrink the ns2.0 surface to the bare minimum the toolchain genuinely requires.

There are two independent forcing functions keeping the floor in place:

1. Fallout.SourceGenerators (a real Roslyn generator). Roslyn analyzers/generators must target netstandard2.0 — they load into the compiler host, which may be .NET Framework (VS / desktop MSBuild); ns2.1/net10 won't load there. That part is immovable. The pain is its dependency cone: it currently references Fallout.Solution, Fallout.Persistence.Solution, Fallout.Utilities, Fallout.Utilities.IO.Globbing, forcing all of them to ns2.0. Investigation shows this cone is pulled solely by StronglyTypedSolutionGenerator (which reads a .sln from disk and emits code) — TransitionShimGenerator (which mirrors types from the live compilation, so it must stay a generator) has zero Fallout.* usings.

2. Fallout.MSBuildTasks (targets net10.0;net472). It references Fallout.Tooling (+ Fallout.Tooling.Generator), which pins Tooling and Utilities to ns2.0. This is the function that actually blocks Configure<T> (in Tooling) and AbsolutePath (in Utilities) from moving to Core. Fallout.Tooling.Generator isn't even a Roslyn generator — it's ns2.0 only because the net472 task consumes it.

⚠️ Consequence to put on record (Visual Studio)

MSBuild tasks load into the MSBuild host that builds the consumer's project. Visual Studio's in-IDE build uses full-framework MSBuild, which cannot load a net10-only task assembly. So dropping the net472 task means the Fallout MSBuild tasks (spec-file tool codegen, pack-tool plumbing) stop working when a consumer builds inside Visual Studio / msbuild.exe. Command-line dotnet build, ./build.ps1, and CI-via-dotnet are unaffected.

We are OK accepting a move away from .NET Framework, but this VS consequence must be a conscious decision. A mitigation that keeps VS working while still freeing the floor: keep a thin task assembly targeting netstandard2.0 (loads in both hosts) that is decoupled from Tooling/Utilities (talks to a minimal ns2.0 shim, or shells out to the net10 Fallout) — so Tooling/Utilities go net10 and only a tiny task DLL stays ns2.0.

Usage Example

Two levers, very different blast radii:

  • Lever 1 — free the SourceGenerators cone (standalone, non-breaking, can land now). Split the generators: TransitionShimGenerator stays a Roslyn generator; StronglyTypedSolutionGenerator moves to a pre-build net10 codegen step (writes Solution.g.cs into obj/, <Compile>-included) or gets a private minimal ns2.0 sln-parser. Either drops the Solution/Persistence/Globbing/Utilities references from the ns2.0 generator project. Build-time only — generated output identical, no public API change.
  • Lever 2 — Fallout.MSBuildTasks off net472 / .NET-only (the larger product decision; unblocks Configure<T> + AbsolutePath → Core). Either drop net472 outright (accepting the VS consequence above) or decouple via a thin ns2.0 task shim so Tooling/Utilities reach net10 while VS keeps working.
  • Once the floor is gone for Tooling/Utilities, the onion/plugin-SDK Core placement (Configure<T>, IAbsolutePath, tool contracts, lifted IFalloutBuild) proceeds cleanly.

The Utilities satellites (Compression/Globbing/Net/Text.*) appear to be ns2.0 by default rather than by force (their only runtime consumer is net10 Fallout.Common), so they should flip to net10 with little risk once the two functions above are resolved.

Alternative

Route around the floor instead of fixing it: use string for paths on the Core surface (no IAbsolutePath), and keep tooling-coupled members like ReportSummary/Configure<T> off the Core IFalloutBuild contract. Zero breakage, but the Core abstraction surface is less ergonomic and the ns2.0 floor (and its drag on the architecture) stays indefinitely.

Could you help with a pull-request?

Yes — Lever 1 can be delivered as a standalone PR immediately; Lever 2 pending the net472 / VS-support decision.

Metadata

Metadata

Labels

enhancementNew feature or requestneeds-triagetarget/2026Targets the 2026 calendar-version line (current). See ADR-0004.

Fields

No fields configured for Feature.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions