From 940785f8946905f3fec0895a4c871371ad1e992f Mon Sep 17 00:00:00 2001 From: Chrison Simtian Date: Fri, 24 Jul 2026 14:57:20 +1200 Subject: [PATCH 1/3] Remove the inherited NUKE telemetry subsystem MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The telemetry feature carried over from NUKE has been inert since the fork: its Application Insights endpoint was the original maintainer's and can't be reused, the client dependency was dropped (#79), and TrackEvent was a stub. It was kept dormant on the intent of wiring up a Fallout-owned backend later — an intent with no owner, endpoint, or plan. Per ADR-0010, Fallout collects no telemetry, so the subsystem is removed rather than left as a dormant liability. Removes the Telemetry classes and the [Telemetry] build extension, every call site (the FalloutBuild attribute, the config-generation hook, and the setup / add-package / cake-convert CLI events), the FALLOUT_TELEMETRY_OPTOUT / NUKE_TELEMETRY_OPTOUT env vars, the FalloutTelemetryVersion / NukeTelemetryVersion MSBuild property (including its legacy lift and FALLOUT001 warning), the FalloutTelemetryDocsUrl constant, and the test-run opt-out plumbing. Not a breaking change: the env var and property only ever gated a no-op, and an unset/unknown one is silently ignored. The .NET SDK's own DOTNET_CLI_TELEMETRY_OPTOUT is left in place. Co-Authored-By: Claude Opus 4.8 (1M context) --- build.ps1 | 1 - build.sh | 1 - build/Build.cs | 3 - build/_build.csproj | 1 - docs/01-getting-started/07-telemetry.md | 84 ---------- src/Fallout.Build.Shared/Constants.cs | 1 - ...dServerConfigurationGenerationAttribute.cs | 1 - .../Extensions/TelemetryAttribute.cs | 26 --- src/Fallout.Build/FalloutBuild.cs | 1 - .../Telemetry/Telemetry.Events.cs | 83 --------- .../Telemetry/Telemetry.Properties.cs | 157 ------------------ src/Fallout.Build/Telemetry/Telemetry.cs | 126 -------------- src/Fallout.Cli/Commands/AddPackageCommand.cs | 1 - .../Commands/CakeConvertCommand.cs | 1 - src/Fallout.Cli/Commands/RunCommand.cs | 1 - src/Fallout.Cli/Commands/SetupCommand.cs | 2 - src/Fallout.Cli/templates/_build.csproj | 1 - src/Fallout.Common/Fallout.Common.targets | 2 - .../ExecutionSpecsInitializer.cs | 15 -- 19 files changed, 508 deletions(-) delete mode 100644 docs/01-getting-started/07-telemetry.md delete mode 100644 src/Fallout.Build/Execution/Extensions/TelemetryAttribute.cs delete mode 100644 src/Fallout.Build/Telemetry/Telemetry.Events.cs delete mode 100644 src/Fallout.Build/Telemetry/Telemetry.Properties.cs delete mode 100644 src/Fallout.Build/Telemetry/Telemetry.cs delete mode 100644 tests/Fallout.Build.Specs/ExecutionSpecsInitializer.cs diff --git a/build.ps1 b/build.ps1 index 0416df15b..3ea0b34c1 100644 --- a/build.ps1 +++ b/build.ps1 @@ -22,7 +22,6 @@ $DotNetChannel = "STS" $env:DOTNET_CLI_TELEMETRY_OPTOUT = 1 $env:DOTNET_NOLOGO = 1 $env:DOTNET_ROLL_FORWARD = "Major" -$env:FALLOUT_TELEMETRY_OPTOUT = 1 ########################################################################### # EXECUTION diff --git a/build.sh b/build.sh index 0008be753..bd0eb8400 100755 --- a/build.sh +++ b/build.sh @@ -18,7 +18,6 @@ DOTNET_CHANNEL="STS" export DOTNET_CLI_TELEMETRY_OPTOUT=1 export DOTNET_NOLOGO=1 export DOTNET_ROLL_FORWARD="Major" -export FALLOUT_TELEMETRY_OPTOUT=1 ########################################################################### # EXECUTION diff --git a/build/Build.cs b/build/Build.cs index fdf7dae5b..7292dff7b 100644 --- a/build/Build.cs +++ b/build/Build.cs @@ -103,9 +103,6 @@ from framework in project.GetTargetFrameworks() [Parameter] public int TestDegreeOfParallelism { get; } = 1; - Configure ITest.TestSettings => _ => _ - .SetProcessEnvironmentVariable("FALLOUT_TELEMETRY_OPTOUT", bool.TrueString); - Target ITest.Test => _ => _ .Inherit() .Partition(2); diff --git a/build/_build.csproj b/build/_build.csproj index e9748ca41..0b0a10b64 100644 --- a/build/_build.csproj +++ b/build/_build.csproj @@ -9,7 +9,6 @@ CS0649;CS0169 .\.. - 1 false false diff --git a/docs/01-getting-started/07-telemetry.md b/docs/01-getting-started/07-telemetry.md deleted file mode 100644 index 8fa6b2ac1..000000000 --- a/docs/01-getting-started/07-telemetry.md +++ /dev/null @@ -1,84 +0,0 @@ ---- -title: Telemetry ---- - -:::warning -**Telemetry is currently a no-op in Fallout.** The previous NUKE telemetry endpoint (Azure Application Insights, owned by the original maintainer) is no longer used. The plumbing on this page describes the framework hooks that *would* fire if a Fallout-controlled endpoint were configured. Today, none is — telemetry short-circuits in the static constructor when no `InstrumentationKey` is set. -::: - -As an effort to improve Fallout and to provide you with a better, more tailored experience, we include a telemetry feature that collects anonymous usage data and enables us to make more informed decisions for the future. - -We want you to be fully aware about telemetry, which is why the global tool will show a disclosure notice on first start. In addition, every build project requires to define a `NukeTelemetryVersion` property: - -```xml title="_build.csproj" - - 1 - -``` - -We will increase the telemetry version whenever we add or change significant data points. With every version change and after updating the `Nuke.Common` package, you will be prompted again for confirmation. - -## Disclosure - -Fallout will display a prompt similar to the following when executing a build project without the `NukeTelemetryVersion` property being set or when executing the global tool for the first time — *once a telemetry endpoint is configured*. - -```text -Telemetry v1 ------------- -Fallout collects anonymous usage data in order to help us improve your experience. -Read more about scope, data points, and opt-out: https://github.com/Fallout-build/Fallout#telemetry -``` - -Once you confirm the notice, Fallout will either: - -- Create an awareness cookie under `~/.fallout/telemetry-awareness/v1` for the respective global tool, or -- Add the `NukeTelemetryVersion` property to the project file. - -## Scope - -As a global tool and library, Fallout has [multiple events](https://github.com/Fallout-build/Fallout/blob/main/src/Nuke.Build/Telemetry/Telemetry.Events.cs) where telemetry is collected: - -- `BuildStarted` – when a build was started -- `TargetSucceeded` – when a target succeeded (only `Restore`, `Compile`, `Test`) -- `BuildSetup` – when setting up a build via `fallout [:setup]` -- `CakeConvert` – when converting Cake files via `fallout :cake-convert` - -:::info -Data for `BuildStarted` and `TargetSucceeded` is only collected when `IsServerBuild` returns `true` (i.e., CI build), or the build is invoked via global tool. I.e., a contributor executing `build.ps1` or `build.sh` will not have telemetry enabled unknowingly. Likewise, when a build project targets a higher telemetry version than the installed global tool, the lower version will be used. -::: - -## Data Points - -The [telemetry data points](https://github.com/Fallout-build/Fallout/blob/main/src/Nuke.Build/Telemetry/Telemetry.Properties.cs) do not collect personal data, such as usernames or email addresses. If we wire up an endpoint, the data will be sent securely to whichever back-end Fallout's maintainers configure — documented here when that happens. - -Protecting your privacy is important to us. If you suspect the telemetry plumbing has been re-enabled incorrectly or could collect sensitive data, file an issue on the [Fallout repository](https://github.com/Fallout-build/Fallout/issues). - -The telemetry feature collects the following data: - -| Version | Data | -|:--------|:------------------------------------------------------------------------------------------| -| All | Timestamp of invocation | -| All | Operating system | -| All | Version of .NET SDK | -| All | Repository provider (GitHub, GitLab, Bitbucket, etc.) | -| All | Repository Branch (`main`, `develop`, `feature`, `hotfix`, custom) | -| All | Hashed Repository URL (SHA256; first 6 characters) | -| All | Hashed Commit Sha (SHA256; first 6 characters) | -| All | Compile time of build project in seconds | -| All | Target framework | -| All | Version of `Nuke.Common` and `Nuke.GlobalTool` | -| All | Host implementation (only non-custom) | -| All | Build type (project/global tool) | -| All | Number of executable targets | -| All | Number of custom extensions | -| All | Number of custom components | -| All | Used configuration generators and build components (only non-custom) | -| All | Target execution time in seconds (only for targets named _Restore_, _Compile_, or _Test_) | - -:::note -Whenever a type does not originate from the `Nuke` namespace, it is replaced with ``. -::: - -## How to opt out - -The telemetry feature is enabled by default. To opt out, set the `FALLOUT_TELEMETRY_OPTOUT` environment variable to `1` or `true`. The legacy `NUKE_TELEMETRY_OPTOUT` name is still honoured during the 10.x line for backwards compatibility, but will be removed in 11.0. diff --git a/src/Fallout.Build.Shared/Constants.cs b/src/Fallout.Build.Shared/Constants.cs index 6df0637e7..9c1750a8c 100644 --- a/src/Fallout.Build.Shared/Constants.cs +++ b/src/Fallout.Build.Shared/Constants.cs @@ -53,7 +53,6 @@ internal static class Constants internal const string FalloutRepositoryGit = $"{FalloutWebsite}.git"; internal const string FalloutRawRepository = $"https://raw.githubusercontent.com/{FalloutOwner}/{FalloutRepoName}/main"; internal const string FalloutDocsUrl = "https://docs.fallout.build/"; - internal const string FalloutTelemetryDocsUrl = $"{FalloutWebsite}#telemetry"; internal const string FalloutNotificationsUrl = $"{FalloutRawRepository}/notifications.json"; // Upstream NUKE references — only for attribution / fallback recognition of legacy project URLs. diff --git a/src/Fallout.Build/CICD/InvokeBuildServerConfigurationGenerationAttribute.cs b/src/Fallout.Build/CICD/InvokeBuildServerConfigurationGenerationAttribute.cs index 371214e87..a2133dfae 100644 --- a/src/Fallout.Build/CICD/InvokeBuildServerConfigurationGenerationAttribute.cs +++ b/src/Fallout.Build/CICD/InvokeBuildServerConfigurationGenerationAttribute.cs @@ -57,7 +57,6 @@ private bool HasConfigurationChanged(IConfigurationGenerator generator) if (changedFiles.Count == 0) return false; - Telemetry.ConfigurationGenerated(generator.HostType, generator.Id, Build); // TODO: multi-line logging Log.Warning("Configuration files for {Configuration} have changed.", generator.DisplayName); changedFiles.ForEach(x => Log.Verbose("Updated {File}", x)); diff --git a/src/Fallout.Build/Execution/Extensions/TelemetryAttribute.cs b/src/Fallout.Build/Execution/Extensions/TelemetryAttribute.cs deleted file mode 100644 index 715e79bfe..000000000 --- a/src/Fallout.Build/Execution/Extensions/TelemetryAttribute.cs +++ /dev/null @@ -1,26 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; - -namespace Fallout.Common.Execution; - -internal class TelemetryAttribute : BuildExtensionAttributeBase, IOnBuildInitialized, IOnTargetSucceeded -{ - public void OnBuildInitialized( - IReadOnlyCollection executableTargets, - IReadOnlyCollection executionPlan) - { - if (Build.IsInterceptorExecution) - return; - - Telemetry.BuildStarted(Build); - } - - public void OnTargetSucceeded(ExecutableTarget target) - { - if (Build.IsInterceptorExecution) - return; - - Telemetry.TargetSucceeded(target, Build); - } -} diff --git a/src/Fallout.Build/FalloutBuild.cs b/src/Fallout.Build/FalloutBuild.cs index a604cccc8..106d7c1cc 100644 --- a/src/Fallout.Build/FalloutBuild.cs +++ b/src/Fallout.Build/FalloutBuild.cs @@ -55,7 +55,6 @@ namespace Fallout.Common; [SerializeBuildGraph(Priority = 20)] [HandlePlanRequests(Priority = 10)] [HandleHelpRequests(Priority = 5)] -[Telemetry] [HandleVisualStudioDebugging] [InjectNonParameterValues(Priority = -100)] // After finish diff --git a/src/Fallout.Build/Telemetry/Telemetry.Events.cs b/src/Fallout.Build/Telemetry/Telemetry.Events.cs deleted file mode 100644 index 7a318978a..000000000 --- a/src/Fallout.Build/Telemetry/Telemetry.Events.cs +++ /dev/null @@ -1,83 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using Fallout.Common.Utilities; -using Fallout.Common.Utilities.Collections; -using Serilog; - -namespace Fallout.Common.Execution; - -internal partial class Telemetry -{ - public static void BuildStarted(IFalloutBuild build) - { - TrackEvent( - eventName: nameof(BuildStarted), - propertiesProvider: () => - GetCommonProperties(build) - .AddDictionary(GetBuildProperties(build)) - .AddDictionary(GetRepositoryProperties(build.RootDirectory))); - } - - public static void TargetSucceeded(ExecutableTarget target, IFalloutBuild build) - { - if (!target.Name.EqualsAnyOrdinalIgnoreCase(knownTargets) || - target.Status != ExecutionStatus.Succeeded) - return; - - TrackEvent( - eventName: nameof(TargetSucceeded), - propertiesProvider: () => - GetCommonProperties(build) - .AddDictionary(GetTargetProperties(build, target)) - .AddDictionary(GetBuildProperties(build)) - .AddDictionary(GetRepositoryProperties(build.RootDirectory))); - } - - public static void ConfigurationGenerated(Type hostType, string generatorId, IFalloutBuild build) - { - TrackEvent( - eventName: nameof(ConfigurationGenerated), - propertiesProvider: () => - GetCommonProperties(build) - .AddDictionary(GetGeneratorProperties(hostType, generatorId)) - .AddDictionary(GetBuildProperties(build)) - .AddDictionary(GetRepositoryProperties(EnvironmentInfo.WorkingDirectory))); - } - - public static void SetupBuild() - { - TrackEvent( - eventName: nameof(SetupBuild), - propertiesProvider: () => - GetCommonProperties() - .AddDictionary(GetRepositoryProperties(EnvironmentInfo.WorkingDirectory))); - } - - public static void ConvertCake() - { - TrackEvent( - eventName: nameof(ConvertCake), - propertiesProvider: () => - GetCommonProperties() - .AddDictionary(GetRepositoryProperties(EnvironmentInfo.WorkingDirectory))); - } - - public static void AddPackage() - { - TrackEvent( - eventName: nameof(AddPackage), - propertiesProvider: () => - GetCommonProperties() - .AddDictionary(GetRepositoryProperties(EnvironmentInfo.WorkingDirectory))); - } - - private static void TrackEvent(string eventName, Func> propertiesProvider) - { - // No-op until a Fallout-controlled telemetry backend lands (#79). Public callers - // (BuildStarted, TargetSucceeded, etc.) stay so we don't have to thread the change - // back through their call sites when telemetry is reintroduced. - _ = eventName; - _ = propertiesProvider; - } -} diff --git a/src/Fallout.Build/Telemetry/Telemetry.Properties.cs b/src/Fallout.Build/Telemetry/Telemetry.Properties.cs deleted file mode 100644 index 23af2222b..000000000 --- a/src/Fallout.Build/Telemetry/Telemetry.Properties.cs +++ /dev/null @@ -1,157 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.Linq; -using System.Reflection; -using System.Runtime.InteropServices; -using Fallout.Common.CI; -using Fallout.Common.Git; -using Fallout.Common.Tooling; -using Fallout.Common.Utilities; -using Fallout.Common.Utilities.Collections; -using Fallout.Common.ValueInjection; - -namespace Fallout.Common.Execution; - -internal partial class Telemetry -{ - private static readonly string[] knownTargets = { "Restore", "Compile", "Test" }; - - private static Dictionary GetCommonProperties(IFalloutBuild build = null) - { - var version = ControlFlow.SuppressErrors( - () => - { - var dotnet = ToolResolver.GetEnvironmentOrPathTool("dotnet"); - return dotnet.Invoke($"--version", logInvocation: false, logOutput: false).StdToText(); - }, - logWarning: false); - - return new Dictionary - { - ["os_platform"] = EnvironmentInfo.Platform.ToString(), - ["os_architecture"] = RuntimeInformation.OSArchitecture.ToString(), - ["version_dotnet_sdk"] = version, - ["version_fallout_common"] = build != null ? typeof(FalloutBuild).Assembly.GetVersionText() : null, - ["version_fallout_global_tool"] = build != null - ? LegacyEnvironment.ReadFromVariables( - EnvironmentInfo.Variables, - Constants.GlobalToolVersionEnvironmentKey, - Constants.LegacyGlobalToolVersionEnvironmentKey) - : Assembly.GetEntryAssembly().GetVersionText() - }; - } - - private static Dictionary GetRepositoryProperties(string directory) - { - var repository = ControlFlow.SuppressErrors(() => GitRepository.FromLocalDirectory(directory), logWarning: false); - if (repository == null) - return new Dictionary(); - - var providers = - new List<(Func, string)> - { - (() => repository.Endpoint?.ContainsOrdinalIgnoreCase("github.com") ?? false, "GitHub"), - (() => repository.Endpoint?.ContainsOrdinalIgnoreCase("gitlab.com") ?? false, "GitLab"), - (() => repository.Endpoint?.ContainsOrdinalIgnoreCase("bitbucket.org") ?? false, "Bitbucket"), - (() => repository.Endpoint?.ContainsOrdinalIgnoreCase("jetbrains.space") ?? false, "JetBrains"), - (() => repository.Endpoint?.ContainsOrdinalIgnoreCase("visualstudio.com") ?? false, "Azure") - }; - - var branches = - new List<(Func, string)> - { - (() => repository.IsOnMainOrMasterBranch(), "main"), - (() => repository.IsOnDevelopBranch(), "develop"), - (() => repository.IsOnReleaseBranch(), "release"), - (() => repository.IsOnHotfixBranch(), "hotfix") - }; - - return new Dictionary - { - ["repo_provider"] = providers.FirstOrDefault(x => x.Item1.Invoke()).Item2, - ["repo_branch"] = branches.FirstOrDefault(x => x.Item1.Invoke()).Item2, - ["repo_url"] = repository.SshUrl?.GetSHA256Hash()[..6], - ["repo_commit"] = repository.Commit?.GetSHA256Hash()[..6] - }; - } - - private static ReadOnlyDictionary GetBuildProperties(IFalloutBuild build) - { - var startTimeString = LegacyEnvironment.ReadFromVariables( - EnvironmentInfo.Variables, - Constants.GlobalToolStartTimeEnvironmentKey, - Constants.LegacyGlobalToolStartTimeEnvironmentKey); - var compileTime = startTimeString != null - ? DateTime.Now.Subtract(DateTime.Parse(startTimeString)) - : default(TimeSpan?); - - return new Dictionary - { - ["compile_time"] = compileTime?.TotalSeconds.ToString("F0"), - ["target_framework"] = EnvironmentInfo.Framework.ToString(), - ["host"] = GetTypeName(build.Host), - ["build_type"] = build.BuildProjectFile != null ? "Project" : "Global Tool", - ["num_targets"] = build.ExecutableTargets.Count.ToString(), - ["num_custom_extensions"] = build.BuildExtensions.Select(x => x.GetType()).Count(IsCustomType).ToString(), - ["num_custom_components"] = build.GetType().GetInterfaces().Count(IsCustomType).ToString(), - ["num_partitioned_targets"] = build.ExecutableTargets.Count(x => x.PartitionSize.HasValue).ToString(), - ["num_secrets"] = ValueInjectionUtility.GetParameterMembers(build.GetType(), includeUnlisted: true) - .Count(x => x.HasCustomAttribute()).ToString(), - ["config_generators"] = build.GetType().GetCustomAttributes() - .Select(GetTypeName).Distinct().OrderBy(x => x).JoinCommaSpace(), - ["build_components"] = build.GetType().GetInterfaces().Where(x => IsCommonType(x) && x != typeof(IFalloutBuild)) - .Select(GetTypeName).Distinct().OrderBy(x => x).JoinCommaSpace() - }.AsReadOnly(); - } - - private static Dictionary GetTargetProperties(IFalloutBuild build, ExecutableTarget target) - { - return new Dictionary - { - ["target_name"] = target.Name, - ["target_duration"] = target.Duration.TotalSeconds.ToString("F0"), - ["target_current_partition"] = build.Partition.Part.ToString(), - ["target_total_partitions"] = build.Partition.Total.ToString() - }; - } - - private static Dictionary GetGeneratorProperties(Type hostType, string generatorId) - { - return new Dictionary - { - ["generator_host"] = GetTypeName(hostType), - ["generator_id"] = generatorId.GetSHA256Hash()[..6] - }; - } - - private static bool IsCommonType(Type type) - { - // Recognize both the new Fallout repository and the legacy NUKE repository — types compiled - // from older NUKE versions still embed the upstream RepositoryUrl in their assembly metadata. - return type.Assembly - .GetCustomAttributes() - .Any(x => x is { Key: "RepositoryUrl" } && - (x.Value == Constants.FalloutRepositoryGit || - x.Value == Constants.UpstreamNukeRepositoryGit)); - } - - private static bool IsCustomType(Type type) - { - return !IsCommonType(type); - } - - private static string GetTypeName(Type type) - { - return IsCommonType(type) - ? type.Name.TrimEnd(nameof(Attribute)) - : type.Descendants(x => x.BaseType).FirstOrDefault(IsCommonType) is { } commonType - ? $"{GetTypeName(commonType)} (Custom)" - : ""; - } - - private static string GetTypeName(object obj) - { - return GetTypeName(obj.GetType()); - } -} diff --git a/src/Fallout.Build/Telemetry/Telemetry.cs b/src/Fallout.Build/Telemetry/Telemetry.cs deleted file mode 100644 index 398461ddf..000000000 --- a/src/Fallout.Build/Telemetry/Telemetry.cs +++ /dev/null @@ -1,126 +0,0 @@ -using System; -using System.Linq; -using System.Reflection; -using System.Threading; -using Fallout.Common.IO; -using Fallout.Solutions; -using Fallout.Common.Utilities; -using static Fallout.Common.ControlFlow; - -namespace Fallout.Common.Execution; - -internal static partial class Telemetry -{ - // https://docs.microsoft.com/en-us/dotnet/core/tools/telemetry - // https://dotnet.microsoft.com/platform/telemetry - // https://docs.microsoft.com/en-us/azure/azure-monitor/app/console - // https://docs.microsoft.com/en-us/azure/azure-monitor/app/ip-collection - - public const string OptOutEnvironmentKey = "FALLOUT_TELEMETRY_OPTOUT"; - public const string LegacyOptOutEnvironmentKey = "NUKE_TELEMETRY_OPTOUT"; - public const int CurrentVersion = 1; - - // Telemetry is currently a no-op for Fallout. The original NUKE maintainer owned an - // Azure Application Insights endpoint we can't reuse; Microsoft.ApplicationInsights was - // dropped from our deps in #79. The awareness/disclosure machinery below stays so we can - // wire up a Fallout-controlled backend later without re-introducing the consent flow. - private const string VersionPropertyName = "FalloutTelemetryVersion"; - private const string LegacyVersionPropertyName = "NukeTelemetryVersion"; - - private static readonly int? confirmedVersion; - - static Telemetry() - { - var optoutParameter = ParameterService.GetParameter(OptOutEnvironmentKey) - ?? ParameterService.GetParameter(LegacyOptOutEnvironmentKey) - ?? string.Empty; - if (optoutParameter == "1" || optoutParameter.EqualsOrdinalIgnoreCase(bool.TrueString)) - return; - - // No telemetry endpoint configured for Fallout yet — short-circuit. When a backend lands, - // re-enable by calling ProjectModelTasks.Initialize() + CheckAwareness() here and wiring - // the resulting consent through to TrackEvent (in Telemetry.Events.cs). - } - - private static int? CheckAwareness() - { - AbsolutePath GetCookieFile(string name, int version) - => Constants.GlobalFalloutDirectory / "telemetry-awareness" / $"v{version}" / name; - - // Check for calls from Fallout.Cli and custom global tools - if (SuppressErrors(() => FalloutBuild.BuildProjectFile, logWarning: false) == null) - { - var cookieName = Assembly.GetEntryAssembly().NotNull().GetName().Name; - var cookieFile = GetCookieFile(cookieName, CurrentVersion); - if (!cookieFile.Exists()) - { - PrintDisclosure($"create awareness cookie for {cookieName.SingleQuote()}"); - cookieFile.TouchFile(); - } - - return CurrentVersion; - } - - var project = ProjectModelTasks.ParseProject(FalloutBuild.BuildProjectFile); - var property = project.Properties.SingleOrDefault(x => x.Name.EqualsOrdinalIgnoreCase(VersionPropertyName)) - ?? project.Properties.SingleOrDefault(x => x.Name.EqualsOrdinalIgnoreCase(LegacyVersionPropertyName)); - if (property?.EvaluatedValue != CurrentVersion.ToString()) - { - if (FalloutBuild.IsServerBuild) - { - PrintDisclosure(action: null); - return null; - } - - PrintDisclosure($"set the {VersionPropertyName.SingleQuote()} property"); - project.SetProperty(VersionPropertyName, CurrentVersion.ToString()); - project.Save(); - } - - for (var version = CurrentVersion; version > 0; version--) - { - var cookieFile = GetCookieFile("Fallout.Cli", version); - if (cookieFile.FileExists()) - return version; - } - - return FalloutBuild.IsServerBuild ? CurrentVersion : null; - } - - private static void PrintDisclosure(string action) - { - var disclosure = - new[] - { - $"Telemetry v{CurrentVersion}", - "------------", - "Fallout collects anonymous usage data in order to help us improve your experience.", - $"Read more about scope, data points, and opt-out: {Constants.FalloutTelemetryDocsUrl}", - string.Empty - }.JoinNewLine(); - - if (action != null && - Environment.UserInteractive && - !Console.IsInputRedirected) - { - Host.Information(disclosure); - Thread.Sleep(2000); - Host.Information($"Press to {action} ..."); - WaitForEnter(); - } - else - { - Host.Warning(disclosure); - Host.Warning("Run in interactive console to fix this warning"); - } - } - - private static void WaitForEnter() - { - ConsoleKey response; - do - { - response = Console.ReadKey(intercept: true).Key; - } while (response != ConsoleKey.Enter); - } -} diff --git a/src/Fallout.Cli/Commands/AddPackageCommand.cs b/src/Fallout.Cli/Commands/AddPackageCommand.cs index d39cc7edc..ec618e954 100644 --- a/src/Fallout.Cli/Commands/AddPackageCommand.cs +++ b/src/Fallout.Cli/Commands/AddPackageCommand.cs @@ -29,7 +29,6 @@ public async Task ExecuteAsync(string[] args, AbsolutePath rootDirectory, A { ToolBanner.Print(); Logging.Configure(); - Telemetry.AddPackage(); ProjectModelTasks.Initialize(); var packageId = args.ElementAt(0); diff --git a/src/Fallout.Cli/Commands/CakeConvertCommand.cs b/src/Fallout.Cli/Commands/CakeConvertCommand.cs index dba41e294..c8101556f 100644 --- a/src/Fallout.Cli/Commands/CakeConvertCommand.cs +++ b/src/Fallout.Cli/Commands/CakeConvertCommand.cs @@ -39,7 +39,6 @@ public async Task ExecuteAsync(string[] args, AbsolutePath rootDirectory, A { ToolBanner.Print(); Logging.Configure(); - Telemetry.ConvertCake(); ProjectModelTasks.Initialize(); Host.Warning( diff --git a/src/Fallout.Cli/Commands/RunCommand.cs b/src/Fallout.Cli/Commands/RunCommand.cs index a98d93fa8..374bbf7ac 100644 --- a/src/Fallout.Cli/Commands/RunCommand.cs +++ b/src/Fallout.Cli/Commands/RunCommand.cs @@ -75,7 +75,6 @@ private static async Task StartDotnetAsync(string dotnet, IEnumerable ExecuteAsync(string[] args, AbsolutePath rootDirectory, A { ToolBanner.Print(); Logging.Configure(); - Telemetry.SetupBuild(); AnsiConsole.WriteLine(); AnsiConsole.MarkupLine("[bold]Let's setup a new build![/]"); @@ -141,7 +140,6 @@ public async Task ExecuteAsync(string[] args, AbsolutePath rootDirectory, A RootDirectory = buildDirectory.GetWinRelativePathTo(rootDirectory), ScriptDirectory = buildDirectory.GetWinRelativePathTo(WorkingDirectory), TargetFramework = TARGET_FRAMEWORK, - TelemetryVersion = Telemetry.CurrentVersion, FalloutVersion = falloutVersion, }))); diff --git a/src/Fallout.Cli/templates/_build.csproj b/src/Fallout.Cli/templates/_build.csproj index 9418f37ac..e529fa8e2 100644 --- a/src/Fallout.Cli/templates/_build.csproj +++ b/src/Fallout.Cli/templates/_build.csproj @@ -7,7 +7,6 @@ CS0649;CS0169;CA1050;CA1822;CA2211;IDE1006 _ROOT_DIRECTORY_ _SCRIPT_DIRECTORY_ - _TELEMETRY_VERSION_ false false false diff --git a/src/Fallout.Common/Fallout.Common.targets b/src/Fallout.Common/Fallout.Common.targets index 4b12c6b45..238b8b38e 100644 --- a/src/Fallout.Common/Fallout.Common.targets +++ b/src/Fallout.Common/Fallout.Common.targets @@ -10,7 +10,6 @@ $(NukeTasksEnabled) $(NukeRootDirectory) $(NukeScriptDirectory) - $(NukeTelemetryVersion) $(NukeDefaultExcludes) $(NukeExcludeBoot) $(NukeExcludeConfig) @@ -90,7 +89,6 @@ <_LegacyFalloutProperty Include="NukeTasksEnabled" Condition="'$(NukeTasksEnabled)' != ''" >FalloutTasksEnabled <_LegacyFalloutProperty Include="NukeRootDirectory" Condition="'$(NukeRootDirectory)' != ''" >FalloutRootDirectory <_LegacyFalloutProperty Include="NukeScriptDirectory" Condition="'$(NukeScriptDirectory)' != ''" >FalloutScriptDirectory - <_LegacyFalloutProperty Include="NukeTelemetryVersion" Condition="'$(NukeTelemetryVersion)' != ''" >FalloutTelemetryVersion <_LegacyFalloutProperty Include="NukeDefaultExcludes" Condition="'$(NukeDefaultExcludes)' != ''" >FalloutDefaultExcludes <_LegacyFalloutProperty Include="NukeExcludeBoot" Condition="'$(NukeExcludeBoot)' != ''" >FalloutExcludeBoot <_LegacyFalloutProperty Include="NukeExcludeConfig" Condition="'$(NukeExcludeConfig)' != ''" >FalloutExcludeConfig diff --git a/tests/Fallout.Build.Specs/ExecutionSpecsInitializer.cs b/tests/Fallout.Build.Specs/ExecutionSpecsInitializer.cs deleted file mode 100644 index 8f39f1338..000000000 --- a/tests/Fallout.Build.Specs/ExecutionSpecsInitializer.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System; -using System.Linq; -using System.Runtime.CompilerServices; -using Fallout.Common.Execution; - -namespace Fallout.Common.Specs; - -public static class ExecutionTestsInitializer -{ - [ModuleInitializer] - public static void Initialize() - { - Environment.SetEnvironmentVariable(Telemetry.OptOutEnvironmentKey, "true"); - } -} From 19f7fd556e01e5713224f6f86c3bac9d100d5132 Mon Sep 17 00:00:00 2001 From: Chrison Simtian Date: Fri, 24 Jul 2026 14:57:20 +1200 Subject: [PATCH 2/3] Strip telemetry knobs on migration instead of renaming them MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The migrate tool rewrote NUKE's telemetry knobs to Fallout-branded equivalents: NukeTelemetryVersion → FalloutTelemetryVersion and NUKE_TELEMETRY_OPTOUT → FALLOUT_TELEMETRY_OPTOUT. With telemetry removed (ADR-0010) those targets no longer exist, so renaming would plant dead, telemetry-branded cruft in every migrated project. Drop the rename rules and strip the knobs instead: RewriteCsprojsStep removes the <(Nuke|Fallout)TelemetryVersion> element line, ScriptRewriter removes any (NUKE|FALLOUT)_TELEMETRY_OPTOUT assignment line (bash/pwsh/cmd spellings). Specs updated to assert the knobs are gone rather than renamed. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../Steps/RewriteCsprojsStep.cs | 18 ++++++++++++-- src/Fallout.Migrate/Steps/ScriptRewriter.cs | 6 ++++- .../MigrationIntegrationSpecs.cs | 2 +- .../RewriteCsprojsStepSpecs.cs | 24 ++++++++++++++++--- .../ScriptRewriterSpecs.cs | 22 ++++++++++++++--- 5 files changed, 62 insertions(+), 10 deletions(-) diff --git a/src/Fallout.Migrate/Steps/RewriteCsprojsStep.cs b/src/Fallout.Migrate/Steps/RewriteCsprojsStep.cs index b462a45cf..37e981525 100644 --- a/src/Fallout.Migrate/Steps/RewriteCsprojsStep.cs +++ b/src/Fallout.Migrate/Steps/RewriteCsprojsStep.cs @@ -34,13 +34,20 @@ internal sealed class RewriteCsprojsStep : IMigrationStep // with the literal "Nuke". private static readonly Regex msBuildPropertyPattern = new( @"\bNuke(?=" + - "(?:RootDirectory|ScriptDirectory|TelemetryVersion|BaseDirectory|BaseNamespace|" + + "(?:RootDirectory|ScriptDirectory|BaseDirectory|BaseNamespace|" + "UseNestedNamespaces|RepositoryUrl|UpdateReferences|ContinueOnError|TaskTimeout|" + "Timeout|TasksEnabled|DefaultExcludes|ExcludeBoot|ExcludeConfig|ExcludeLogs|" + "ExcludeDirectoryBuild|ExcludeCi|SpecificationFiles|ExternalFiles|TasksAssembly|" + "TasksDirectory)\\b)", RegexOptions.Compiled); + // Strip the telemetry-version property entirely — telemetry was removed from Fallout + // (ADR-0010), so a migrated project must not carry a dead . + // Matches the whole element line (either legacy Nuke* or already-Fallout* spelling). + private static readonly Regex telemetryVersionPropertyPattern = new( + @"^[ \t]*<(?(?:Nuke|Fallout)TelemetryVersion)>.*?>\s*\r?\n?", + RegexOptions.Compiled | RegexOptions.Multiline); + // Strip explicit `System.Security.Cryptography.Xml` PackageReferences. NUKE-era projects // often pinned this directly at an older major (e.g. 9.x). Fallout.Common 10.2.12+ transitively // requires a newer version (10.0.6+) and the conflict trips NU1605 ("Detected package @@ -102,7 +109,14 @@ public static RewriteResult Rewrite(string original, string falloutVersion) return "Fallout"; }); - // Pass 3 — strip the stale System.Security.Cryptography.Xml direct pin. + // Pass 3 — strip the telemetry-version property (feature removed in ADR-0010). + content = telemetryVersionPropertyPattern.Replace(content, _ => + { + edits++; + return string.Empty; + }); + + // Pass 4 — strip the stale System.Security.Cryptography.Xml direct pin. content = cryptographyXmlPackageRefPattern.Replace(content, _ => { edits++; diff --git a/src/Fallout.Migrate/Steps/ScriptRewriter.cs b/src/Fallout.Migrate/Steps/ScriptRewriter.cs index ac3fbe25a..2e681a3c1 100644 --- a/src/Fallout.Migrate/Steps/ScriptRewriter.cs +++ b/src/Fallout.Migrate/Steps/ScriptRewriter.cs @@ -13,12 +13,16 @@ internal static class ScriptRewriter /// The ordered find/replace patterns applied by . private static readonly (Regex Pattern, string Replacement)[] patterns = { + // Strip any telemetry opt-out line entirely — telemetry was removed from Fallout + // (ADR-0010), so there is nothing to opt out of. Handles bash `export`, PowerShell + // `$env:`, and cmd `set` spellings by matching the whole line. Runs before the + // env-var renames below so the line is gone rather than renamed to a dead variable. + (new Regex(@"^.*\b(?:NUKE|FALLOUT)_TELEMETRY_OPTOUT\b.*\r?\n?", RegexOptions.Compiled | RegexOptions.Multiline), ""), // `dotnet nuke` invocations (new Regex(@"\bdotnet\s+nuke\b", RegexOptions.Compiled), "dotnet fallout"), // .nuke directory references → .fallout (new Regex(@"(?<=[\\/.""'\s])\.nuke(?=[\\/""'\s])", RegexOptions.Compiled), ".fallout"), // Legacy env vars (consumer-facing ones from P3.5c) - (new Regex(@"\bNUKE_TELEMETRY_OPTOUT\b", RegexOptions.Compiled), "FALLOUT_TELEMETRY_OPTOUT"), (new Regex(@"\bNUKE_GLOBAL_TOOL_VERSION\b", RegexOptions.Compiled), "FALLOUT_GLOBAL_TOOL_VERSION"), (new Regex(@"\bNUKE_GLOBAL_TOOL_START_TIME\b", RegexOptions.Compiled), "FALLOUT_GLOBAL_TOOL_START_TIME"), (new Regex(@"\bNUKE_INTERNAL_INTERCEPTOR\b", RegexOptions.Compiled), "FALLOUT_INTERNAL_INTERCEPTOR"), diff --git a/tests/Fallout.Migrate.Specs/MigrationIntegrationSpecs.cs b/tests/Fallout.Migrate.Specs/MigrationIntegrationSpecs.cs index 53a937e8e..117c4234a 100644 --- a/tests/Fallout.Migrate.Specs/MigrationIntegrationSpecs.cs +++ b/tests/Fallout.Migrate.Specs/MigrationIntegrationSpecs.cs @@ -34,7 +34,7 @@ public async Task MigratesVanillaConsumerRepo() var buildSh = File.ReadAllText(Path.Combine(temp, "build.sh")); buildSh.Should().Contain("dotnet fallout"); - buildSh.Should().Contain("FALLOUT_TELEMETRY_OPTOUT"); + buildSh.Should().NotContain("TELEMETRY_OPTOUT"); // telemetry removed — opt-out stripped, not renamed (ADR-0010) buildSh.Should().Contain(".fallout/temp"); // .nuke/ moved to .fallout/. diff --git a/tests/Fallout.Migrate.Specs/RewriteCsprojsStepSpecs.cs b/tests/Fallout.Migrate.Specs/RewriteCsprojsStepSpecs.cs index e11732f9f..8a09aa9d3 100644 --- a/tests/Fallout.Migrate.Specs/RewriteCsprojsStepSpecs.cs +++ b/tests/Fallout.Migrate.Specs/RewriteCsprojsStepSpecs.cs @@ -35,20 +35,38 @@ public void RewritesNukeRootDirectoryProperty() .\.. - 1 """; var result = RewriteCsprojsStep.Rewrite(input, TestFalloutVersion); - result.EditCount.Should().Be(4); // 2 opening + 2 closing tags + result.EditCount.Should().Be(2); // 1 opening + 1 closing tag result.Content.Should().Contain(""); result.Content.Should().Contain(""); - result.Content.Should().Contain(""); result.Content.Should().NotContain(""); } + [Fact] + public void StripsTelemetryVersionProperty() + { + // Telemetry was removed from Fallout (ADR-0010): NukeTelemetryVersion is dropped, not + // renamed to a dead FalloutTelemetryVersion. Sibling properties are left intact. + const string input = """ + + + .\.. + 1 + + + """; + + var result = RewriteCsprojsStep.Rewrite(input, TestFalloutVersion); + + result.Content.Should().NotContain("TelemetryVersion"); + result.Content.Should().Contain(""); + } + [Fact] public void LeavesUnrelatedNukePrefixedIdentifiersAlone() { diff --git a/tests/Fallout.Migrate.Specs/ScriptRewriterSpecs.cs b/tests/Fallout.Migrate.Specs/ScriptRewriterSpecs.cs index f9f4956a2..18846e013 100644 --- a/tests/Fallout.Migrate.Specs/ScriptRewriterSpecs.cs +++ b/tests/Fallout.Migrate.Specs/ScriptRewriterSpecs.cs @@ -27,16 +27,32 @@ public void RewritesDotDirectoryReferences() public void RewritesLegacyEnvVars() { const string input = """ - export NUKE_TELEMETRY_OPTOUT=1 $env:NUKE_GLOBAL_TOOL_VERSION = "10.0" """; var result = ScriptRewriter.Rewrite(input); - result.EditCount.Should().Be(2); - result.Content.Should().Contain("FALLOUT_TELEMETRY_OPTOUT"); + result.EditCount.Should().Be(1); result.Content.Should().Contain("FALLOUT_GLOBAL_TOOL_VERSION"); } + [Fact] + public void StripsTelemetryOptOutLineEntirely() + { + // Telemetry was removed from Fallout (ADR-0010) — the opt-out is dropped, not renamed + // to a dead FALLOUT_TELEMETRY_OPTOUT. The surrounding lines are untouched. + const string input = """ + export DOTNET_ROLL_FORWARD="Major" + export NUKE_TELEMETRY_OPTOUT=1 + dotnet nuke "$@" + """; + + var result = ScriptRewriter.Rewrite(input); + + result.Content.Should().NotContain("TELEMETRY_OPTOUT"); + result.Content.Should().Contain("DOTNET_ROLL_FORWARD"); + result.Content.Should().Contain("dotnet fallout"); + } + [Fact] public void LeavesPlainWordNukeAlone() { From ad698769c2409f5e3e06fa0829c8406c6187632f Mon Sep 17 00:00:00 2001 From: Chrison Simtian Date: Fri, 24 Jul 2026 14:57:20 +1200 Subject: [PATCH 3/3] Document the no-telemetry decision (ADR-0010) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Records the decision that Fallout collects no telemetry — reversing the prior "kept dormant, wire up a Fallout endpoint later" stance — and its rationale, non-breaking impact, and the alternatives (keep dormant / opt-in / local-only) that were rejected. Adds a "No telemetry" convention, drops the now-removed Microsoft.ApplicationInsights row from the dependency overview, updates the from-nuke migration guide to show the telemetry knobs are stripped, and rewords the build-events example that used telemetry as its illustration. Co-Authored-By: Claude Opus 4.8 (1M context) --- docs/02-fundamentals/04-builds.md | 2 +- docs/adr/0010-no-telemetry-collection.md | 72 ++++++++++++++++++++++++ docs/adr/README.md | 1 + docs/agents/conventions.md | 2 +- docs/dependencies.md | 6 -- docs/migration/from-nuke.md | 9 +-- 6 files changed, 80 insertions(+), 12 deletions(-) create mode 100644 docs/adr/0010-no-telemetry-collection.md diff --git a/docs/02-fundamentals/04-builds.md b/docs/02-fundamentals/04-builds.md index 8eb8bf70a..f6b89d04c 100644 --- a/docs/02-fundamentals/04-builds.md +++ b/docs/02-fundamentals/04-builds.md @@ -116,7 +116,7 @@ You can examine the status of targets by using any of the appropriate `ICollecti ## Build Events -For implementing cross-cutting concerns, like telemetry and similar, you can hook into various build events: +For implementing cross-cutting concerns, like logging or notifications, you can hook into various build events: ```csharp title="FalloutBuild.cs" abstract class FalloutBuild diff --git a/docs/adr/0010-no-telemetry-collection.md b/docs/adr/0010-no-telemetry-collection.md new file mode 100644 index 000000000..face96b44 --- /dev/null +++ b/docs/adr/0010-no-telemetry-collection.md @@ -0,0 +1,72 @@ +# ADR-0010 — Fallout collects no telemetry + +- **Status:** Accepted +- **Date:** 2026-07-24 +- **Deciders:** Fallout maintainers +- **Relates to:** [#79](https://github.com/Fallout-build/Fallout/issues/79) (drop the dead `Microsoft.ApplicationInsights` dependency — subsumed by this decision), the removed `docs/01-getting-started/07-telemetry.md`. + +## Context + +NUKE shipped a telemetry subsystem (added upstream in 2021): a `[Telemetry]` build extension plus global-tool hooks that gathered anonymous usage data — OS/SDK versions, build shape (target/component counts), hashed repo/commit fingerprints — and sent it to an **Azure Application Insights** instance owned personally by the original maintainer, behind a first-run disclosure/consent flow and a `NUKE_TELEMETRY_OPTOUT` opt-out. + +Fallout inherited all of it, but it has been **inert since the fork**: + +- The Application Insights instrumentation key was matkoch-owned and cannot be reused, so `Microsoft.ApplicationInsights` was dropped from dependencies ([#79](https://github.com/Fallout-build/Fallout/issues/79)) and `TrackEvent` became a stub that discards its inputs. +- The static constructor short-circuits before the consent flow ever runs — no disclosure prompt, no awareness cookie. +- Nothing is collected and nothing is transmitted anywhere. + +The scaffolding was nonetheless **kept on purpose**, on the stated intent of wiring up a "Fallout-controlled backend later." That intent never acquired an owner, an endpoint, or a concrete plan — it was a standing *maybe*. Meanwhile the dormant code was a liability: it still assembled usage properties on the hot build path, it carried a re-enable comment that invited someone to flip it back on, and it kept a consumer-facing surface (`FALLOUT_TELEMETRY_OPTOUT`, `FalloutTelemetryVersion`, disclosure copy) alive for a feature that does nothing. + +## Decision + +**Fallout collects no telemetry — now or as a matter of standing policy for this fork — and the inherited subsystem is removed in full rather than left dormant.** + +- No usage data is gathered, and nothing phones home. A build framework people run in CI and on their own machines should not be a data-collection channel; for a hard-fork rebuilding trust, "we collect nothing" is a simpler and stronger promise than "we collect anonymized data you can opt out of." +- Because there is nothing to opt out of, there is no opt-out. The `FALLOUT_TELEMETRY_OPTOUT` / legacy `NUKE_TELEMETRY_OPTOUT` env vars and the `FalloutTelemetryVersion` / `NukeTelemetryVersion` MSBuild property are removed along with the code that read them. +- Dormant scaffolding is not kept "just in case." If Fallout ever wants usage insight, that is a fresh decision requiring its own ADR and an **opt-in**, fully-documented design with a named endpoint and owner — not the revival of this code. + +### Removed surface + +- The `Telemetry` subsystem (`Telemetry`, `Telemetry.Events`, `Telemetry.Properties`) and the `[Telemetry]` build extension. +- All call sites: the `[Telemetry]` attribute on `FalloutBuild`, the config-generation hook, and the `setup` / `add-package` / `cake-convert` CLI events. +- `FALLOUT_TELEMETRY_OPTOUT` / `NUKE_TELEMETRY_OPTOUT`, `FalloutTelemetryVersion` / `NukeTelemetryVersion`, the `FalloutTelemetryDocsUrl` constant, and the test-run opt-out plumbing. +- The telemetry documentation page. +- The `fallout migrate` tool now **strips** NUKE's telemetry knobs from migrated projects instead of renaming them to dead `Fallout*` equivalents. + +## Consequences + +### Positive + +- **Zero data collection**, and no privacy footgun — the "someone re-enables it incorrectly" path is gone because there is no code to re-enable. +- Smaller surface: dead code, a dead dependency ([#79](https://github.com/Fallout-build/Fallout/issues/79)), a consent UX, and several consumer-facing knobs all removed. +- Migrated NUKE projects come out clean — no telemetry-branded cruft carried across. + +### Negative + +- We forgo the aggregate usage insight telemetry could (in principle) have provided. Accepted: it was never actually flowing, and prioritization has done fine without it. +- Reintroducing any metrics later means starting from a clean, opt-in design — deliberately more work than flipping a dormant switch. That friction is the point. + +### Neutral + +- Removing the opt-out env var and the MSBuild property is **not a breaking change**: both only ever gated a no-op, and an unset/unknown env var or MSBuild property is silently ignored — no consumer build errors. The `FALLOUT001` legacy-property warning simply stops firing for `NukeTelemetryVersion`. +- `DOTNET_CLI_TELEMETRY_OPTOUT` (the **.NET SDK's** telemetry, unrelated to Fallout's) is left in place in the bootstrap scripts and generated CI — we still disable that. + +## Alternatives considered + +### A. Keep the scaffolding dormant, wire up a Fallout-owned endpoint later (the prior stance — rejected) + +This is what the code and docs described. **Rejected** because the "later" had no owner, endpoint, or timeline; the dormant code was a live liability (hot-path property assembly, a re-enable invitation, consumer-facing knobs for a no-op); and keeping consent/opt-out machinery for a feature that does nothing is confusing. A future decision to collect data should be made explicitly, not pre-wired. + +### B. Ship opt-in telemetry with a Fallout endpoint (rejected for now) + +Stand up an opt-in, Fallout-owned analytics pipeline. **Rejected** — no compelling need for a build framework, and it is out of scope for the rebrand/foundation work. Not foreclosed forever: it would require its own ADR superseding this one, and would have to be opt-in by construction. + +### C. Local-only anonymized stats (rejected) + +Collect stats to a local file for the user's own inspection, never transmitted. **Rejected** as scope creep with no demonstrated demand; nothing stops a consumer from building this themselves via the public build-event hooks. + +## References + +- [#79](https://github.com/Fallout-build/Fallout/issues/79) — drop the dead `Microsoft.ApplicationInsights` dependency (subsumed here) +- [docs/agents/conventions.md](../agents/conventions.md) — "No telemetry" convention +- [docs/migration/from-nuke.md](../migration/from-nuke.md) — telemetry knobs are stripped on migration diff --git a/docs/adr/README.md b/docs/adr/README.md index a932561f3..811242dec 100644 --- a/docs/adr/README.md +++ b/docs/adr/README.md @@ -40,3 +40,4 @@ If you change a decision, do NOT silently rewrite the old ADR — add a new one | [0004](0004-calendar-versioning-and-dual-pace-channels.md) | Calendar versioning + dual-pace channels (edge/stable) + experimental APIs | Accepted (§3 amended by 0007; channel ladder §2 superseded by 0008) | | [0007](0007-cut-release-branch-on-demand.md) | Cut `release/YYYY` on demand, not preemptively | Accepted | | [0008](0008-collapse-experimental-into-main.md) | Collapse `experimental` into `main`; `main` is the sole prerelease lane | Accepted | +| [0010](0010-no-telemetry-collection.md) | Fallout collects no telemetry | Accepted | diff --git a/docs/agents/conventions.md b/docs/agents/conventions.md index 091f23fc8..6bf8499f1 100644 --- a/docs/agents/conventions.md +++ b/docs/agents/conventions.md @@ -10,7 +10,7 @@ Three groups: conventions to respect, things never to do, and the tool-wrapper r - **Tool wrappers**: copy/paste from neighbours; cover full commands; use ``, ``, `
    `/`
      `, ``, `` in `help`; don't write `secret: false` or `default: xxx`. See [Tool wrapper recipe](#tool-wrapper-recipe) below. - **Tests next to code, separate folder**: every `Foo` project under `src/` has a sibling `Foo.Tests` project under `tests/`. Mirror the namespace. - **No IDE-specific style files committed.** `.editorconfig` and `*.DotSettings` were removed during the takeover — relying on `dotnet format` defaults and review. -- **Telemetry opt-out is set in test runs** (`FALLOUT_TELEMETRY_OPTOUT=true`). Keep it that way. +- **No telemetry.** Fallout collects no usage data ([ADR-0010](../adr/0010-no-telemetry-collection.md)). The inherited NUKE telemetry subsystem, its opt-out env var, and the `FalloutTelemetryVersion` property were removed — don't reintroduce any of them. - **No per-file license headers.** The MIT notice lives in [`LICENSE`](https://github.com/Fallout-build/Fallout/blob/main/LICENSE) at the repo root, and NuGet packages declare MIT via `PackageLicenseExpression`. Per-file headers were stripped in v11 (one source of truth + the header URL would have rotted on the repo-org transfer). Vendored third-party code keeps its own copyright headers — don't touch those (e.g. files under `src/Persistence/Fallout.Persistence.Solution/` retain Microsoft's MIT notice). - **`[Experimental]` for opt-in unstable public APIs.** Not-yet-stable public surface is marked with `[Experimental("FALLOUT0xx")]` rather than held back or shipped silently. See [the `[Experimental]` convention](#experimental-for-opt-in-unstable-apis) below and the [diagnostic-ID registry](../experimental-apis.md). - **`[Obsolete]` with a `DiagnosticId` for deprecations.** Deprecated public surface carries `[Obsolete(..., DiagnosticId = "FALLOUTOBS0xx")]` so `TreatWarningsAsErrors` consumers can suppress a single deprecation. See [the `[Obsolete]` convention](#obsolete-for-deprecating-public-apis) below and the [diagnostic-ID registry](../obsolete_apis.md). diff --git a/docs/dependencies.md b/docs/dependencies.md index e88890001..e7dd1fb05 100644 --- a/docs/dependencies.md +++ b/docs/dependencies.md @@ -64,12 +64,6 @@ Central package versions are pinned in `Directory.Packages.props`; this page lin |---|---| | `NuGet.Packaging` | Read .nupkg metadata. Used by `NuGetVersionResolver`, `ProjectUpdater`. | -## Telemetry — currently inactive - -| Package | Purpose | Status | -|---|---|---| -| `Microsoft.ApplicationInsights` | Telemetry client | **Dead weight today.** `Telemetry.cs` short-circuits because `InstrumentationKey = ""` (the original NUKE key was matkoch-owned, we don't reuse). Removal tracked in [#79](https://github.com/Fallout-build/Fallout/issues/79). Re-introduce when we stand up a Fallout-owned endpoint. | - ## Vendored source | Package | Source | Why vendored | diff --git a/docs/migration/from-nuke.md b/docs/migration/from-nuke.md index bca967975..b8663da7b 100644 --- a/docs/migration/from-nuke.md +++ b/docs/migration/from-nuke.md @@ -66,8 +66,9 @@ If your build had previously worked against NUKE, it should now work against Fal | Fully-qualified type refs | `Nuke.Common.AbsolutePath` | `Fallout.Common.AbsolutePath` | | Base class name | `: NukeBuild` | `: FalloutBuild` | | Base interface name | `: INukeBuild` | `: IFalloutBuild` | -| MSBuild properties in `_build.csproj` | ``, `` | ``, `` | -| Bootstrap scripts | `dotnet nuke`, `NUKE_TELEMETRY_OPTOUT`, `.nuke/temp` | `dotnet fallout`, `FALLOUT_TELEMETRY_OPTOUT`, `.fallout/temp` | +| MSBuild properties in `_build.csproj` | `` | `` | +| Bootstrap scripts | `dotnet nuke`, `.nuke/temp` | `dotnet fallout`, `.fallout/temp` | +| Telemetry knobs (removed) | ``, `NUKE_TELEMETRY_OPTOUT` | *dropped* — Fallout has no telemetry ([ADR-0010](../adr/0010-no-telemetry-collection.md)); `fallout migrate` strips them | | Config directory | `.nuke/` | `.fallout/` (contents preserved) | The 1:1 namespace prefix swap is the only structural change. Type names (other than `NukeBuild` / `INukeBuild`) keep their identifiers — `[Parameter]`, `[Solution]`, `[GitHubActions]`, `Solution`, `GitRepository`, etc. all stay the same. @@ -103,9 +104,9 @@ You'll need a GitHub Personal Access Token with the `read:packages` scope. Then If you'd rather drive the rewrite by hand (small projects, or you want to learn what the tool does): -1. Edit `build/_build.csproj`. For every ``, change `Nuke.X` → `Fallout.X`. Same for `` / `` MSBuild properties. +1. Edit `build/_build.csproj`. For every ``, change `Nuke.X` → `Fallout.X`. Same for the `` MSBuild property. Delete any `` — Fallout has no telemetry ([ADR-0010](../adr/0010-no-telemetry-collection.md)). 2. In every `.cs` file under `build/`, change `using Nuke.X.Y;` to `using Fallout.X.Y;`. Replace `: NukeBuild` with `: FalloutBuild` and `INukeBuild` with `IFalloutBuild`. -3. In `build.ps1`, `build.sh`, `build.cmd`: `dotnet nuke` → `dotnet fallout`, `NUKE_TELEMETRY_OPTOUT` → `FALLOUT_TELEMETRY_OPTOUT`, `.nuke/temp` → `.fallout/temp`. +3. In `build.ps1`, `build.sh`, `build.cmd`: `dotnet nuke` → `dotnet fallout`, `.nuke/temp` → `.fallout/temp`. Delete any `NUKE_TELEMETRY_OPTOUT` line (no telemetry to opt out of). 4. Rename the `.nuke/` directory to `.fallout/`. Contents are preserved. 5. Run `./build.ps1` to verify.