From e1213f28eaae7ff4c991cd5988de25e4a800c08a Mon Sep 17 00:00:00 2001 From: Chrison Simtian Date: Thu, 25 Jun 2026 13:37:11 +1200 Subject: [PATCH 1/3] Re-introduce JetBrains.Annotations and mark outer-layer assemblies [PublicAPI] Reverses the rebrand-era removal (CHANGELOG #76). Adds JetBrains.Annotations centrally and stamps [assembly: PublicAPI] on the consumer-facing "outer layer" so Rider/ReSharper treat their public surface as intentional API. Outer-layer membership is a single list in Directory.Build.props (_FalloutOuterApiAssemblies); inner layers (MSBuildTasks, SourceGenerators, the Cli/Migrate tools, Migrate.Analyzers, the Persistence.Solution parser) get no blanket annotation and are annotated selectively in source. The reference flows to consumers (no PrivateAssets) so their tooling sees the annotations too. Co-Authored-By: Claude Opus 4.8 (1M context) --- Directory.Build.props | 18 ++++++++++++++++++ Directory.Packages.props | 1 + 2 files changed, 19 insertions(+) diff --git a/Directory.Build.props b/Directory.Build.props index 0c8259874..afdfc3ac1 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -69,4 +69,22 @@ + + + <_FalloutOuterApiAssemblies>;Fallout.Common;Fallout.Build;Fallout.Build.Shared;Fallout.Components;Fallout.Core;Fallout.Tooling;Fallout.ProjectModel;Fallout.Utilities;Fallout.Utilities.IO.Compression;Fallout.Utilities.IO.Globbing;Fallout.Utilities.Net;Fallout.Utilities.Text.Json;Fallout.Utilities.Text.Yaml;Fallout.Solution;Fallout.NuGet.Analysis;Fallout.Tooling.Generator;Nuke.Common;Nuke.Build;Nuke.Components; + true + + + + + + + + diff --git a/Directory.Packages.props b/Directory.Packages.props index 644d92315..089b70214 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -13,6 +13,7 @@ + From f72c671662dc226083d517007192d88f3925abf4 Mon Sep 17 00:00:00 2001 From: Chrison Simtian Date: Thu, 25 Jun 2026 14:01:32 +1200 Subject: [PATCH 2/3] Internalize implementation-detail types in inner-layer assemblies Non-breaking encapsulation pass on assemblies with no consumer-facing API (audit Tier 1). These were public by accident, not by design: - Fallout.MSBuildTasks.TaskItemExtensions (not packed; in-assembly helper) - Fallout.SourceGenerators.CodeAnalysisExtensions (not packed; in-assembly helper) - Fallout.Migrate.Migration + nested Summary (tool exe; used only by Program and the test project via InternalsVisibleTo) Migration is internalized alongside its Summary return type to keep accessibility consistent (CS0050). Migrate.Tests reach both via the existing IVT grant. Co-Authored-By: Claude Opus 4.8 (1M context) --- src/Fallout.MSBuildTasks/TaskItemExtensions.cs | 2 +- src/Fallout.Migrate/Migration.cs | 4 ++-- src/Fallout.SourceGenerators/CodeAnalysisExtensions.cs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Fallout.MSBuildTasks/TaskItemExtensions.cs b/src/Fallout.MSBuildTasks/TaskItemExtensions.cs index 9ec6b435f..f8db05d03 100644 --- a/src/Fallout.MSBuildTasks/TaskItemExtensions.cs +++ b/src/Fallout.MSBuildTasks/TaskItemExtensions.cs @@ -4,7 +4,7 @@ namespace Fallout.MSBuildTasks; -public static class TaskItemExtensions +internal static class TaskItemExtensions { public static string GetMetadataOrNull(this ITaskItem taskItem, string metdataName) { diff --git a/src/Fallout.Migrate/Migration.cs b/src/Fallout.Migrate/Migration.cs index 939b849f8..26fd45b21 100644 --- a/src/Fallout.Migrate/Migration.cs +++ b/src/Fallout.Migrate/Migration.cs @@ -5,7 +5,7 @@ namespace Fallout.Migrate; -public sealed class Migration +internal sealed class Migration { private readonly string _rootDirectory; private readonly bool _dryRun; @@ -144,7 +144,7 @@ private string RelativePath(string absolute) => private void Log(string line) => _log.WriteLine(line); - public sealed class Summary + internal sealed class Summary { public int FilesChanged { get; set; } public int EditCount { get; set; } diff --git a/src/Fallout.SourceGenerators/CodeAnalysisExtensions.cs b/src/Fallout.SourceGenerators/CodeAnalysisExtensions.cs index a00c38fff..c96750a9c 100644 --- a/src/Fallout.SourceGenerators/CodeAnalysisExtensions.cs +++ b/src/Fallout.SourceGenerators/CodeAnalysisExtensions.cs @@ -6,7 +6,7 @@ namespace Fallout.SourceGenerators; -public static class CodeAnalysisExtensions +internal static class CodeAnalysisExtensions { public static IEnumerable GetAllNamespaces(this INamespaceSymbol namespaceSymbol) { From dfc01f8c37de50712dead6795e6af61067734dae Mon Sep 17 00:00:00 2001 From: Chrison Simtian Date: Thu, 25 Jun 2026 14:02:29 +1200 Subject: [PATCH 3/3] Add API encapsulation audit doc (tracks the deferred internalizations) Records the public-by-accident audit behind the [PublicAPI] pass: Tier 1 done (non-breaking inner-layer flips), Tier 2 deferred (breaking, batched to the year cut), Tier 3 kept public (CI-config extensibility surface). Substitutes for a tracking issue since issues are disabled on this fork. Co-Authored-By: Claude Opus 4.8 (1M context) --- docs/api-encapsulation-audit.md | 52 +++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 docs/api-encapsulation-audit.md diff --git a/docs/api-encapsulation-audit.md b/docs/api-encapsulation-audit.md new file mode 100644 index 000000000..9690d4bfb --- /dev/null +++ b/docs/api-encapsulation-audit.md @@ -0,0 +1,52 @@ +# API encapsulation audit + +Companion to the `[PublicAPI]` annotation pass (PR #6). Stamping `[assembly: PublicAPI]` +on the outer (consumer-facing) layer declares each assembly's **entire** public surface as +intentional API. This audit records public types that are `public` by accident and the +decisions taken. (GitHub issues are disabled on this fork, so this doc is the tracker.) + +> **Caveat that drives every call here:** repo-only grep is insufficient for a framework. +> A type with zero in-repo references can be internal plumbing **or** an extensibility +> surface only external consumers touch. Verify intent (NUKE history, `public`/`protected +> virtual` reachability) before flipping anything in an outer assembly. + +## Tier 1 — done (non-breaking, inner-layer assemblies) + +Flipped to `internal` in PR #6 (no consumer-facing API in these assemblies): + +| Type | Assembly | Note | +|---|---|---| +| `TaskItemExtensions` | `Fallout.MSBuildTasks` | not packed; in-assembly helper | +| `CodeAnalysisExtensions` | `Fallout.SourceGenerators` | not packed; in-assembly helper | +| `Migration` + nested `Summary` | `Fallout.Migrate` | tool exe; used only by `Program` + tests (IVT). `Migration` internalized with `Summary` to keep accessibility consistent (CS0050) | + +## Tier 2 — deferred (breaking; batch to the yearly major cut) + +High-confidence implementation details, but in **outer/packed** assemblies — flipping is +breaking, so it follows the breaking-change flow (gate behind `[Experimental(...)]` or hold +on a topic branch; CHANGELOG + `breaking-change` label at PR time). + +**`Fallout.Build`** +- `InMemorySink` (`Logging.cs`) — nested log sink, in-assembly only +- `ConsoleUtility` (`Utilities/ConsoleUtility.cs`) — console I/O helper, in-assembly only +- `Terminal` + `Terminal.Rider` / `Terminal.VSCode` / `Terminal.VisualStudio` (`Terminal.cs`) — env-detection markers + +**`Fallout.Persistence.Solution`** (csproj already documents intent to narrow these) +- `StringTable`, `PathShim`, `Extensions` + +Before flipping: confirm no external consumer usage and no extensibility reachability for each. + +## Tier 3 — keep public (intentional extensibility; not candidates) + +The ~49 CI Configuration types (`*Step` / `*Trigger` / `*Job` / `*Parameter` / `*Dependency` ++ abstract bases under `Fallout.Common/CI/**/Configuration/`) and abstract attribute bases +(`FileSystemGlobbingAttributeBase`, `AzureKeyVaultAttributeBase`). These are unreferenced +in-repo precisely *because* only external consumers use them: consumers subclass e.g. +`GitHubActionsAttribute`, override `public override ConfigurationEntity GetConfiguration(...)`, +and build these objects. The blanket `[assembly: PublicAPI]` is correct for them — it stops +Rider flagging them as unused. **No action.** + +## Clean + +`Fallout.Components`, `Fallout.Core`, `Fallout.Tooling`, `Fallout.ProjectModel`, all +`Fallout.Utilities*`, and the `Fallout.Solution` facade audited clean — no accidental publics.