From 8ad7368d42f0650871ca81446f58c7c75c62ee93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pedro=20Hern=C3=A1ndez?= Date: Mon, 7 Sep 2026 14:39:40 -0400 Subject: [PATCH] `signsofai --version` has said 0.1.0 since 0.1.0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `Program.cs` restated the version as a constant and nobody ever bumped it. The package has gone out as 0.2.0 through 0.7.0 while the tool told anyone who asked that they were running the first release ever published. That is the failure mode from 24 August, one channel over. A support message then said "desktop 0.4.0 is not published" because the desktop app displayed no version at all and the reporter could not tell which build they had. #64 fixed that one and added a guard. Nobody looked at the CLI. It is worse here than there. The desktop said nothing; the CLI says something false. Someone checking whether they already have today's em-dash fix runs `--version`, reads 0.1.0, and concludes they are seven releases behind when they are current. `BuildInfo` reads the assembly the compiler stamped from ``, so the two cannot disagree — the same reasoning `DesktopRelease.ZipUrl` uses to interpolate its URL instead of restating it. The guard runs the tool that was just built and compares what it says against what the csproj packs. Verified by mutation: with the constant put back, the step fails with 0.1.0 against 0.7.0. A test asserting the source does not contain a literal would have been satisfied by a comment. Found while verifying that 0.7.0 on NuGet actually carried the em-dash fix. It does — the learner's essay comes back with no em-dash finding from the published package. The version it reported while proving it was 0.1.0. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_015PEbbiYSNPw7jE3LrPNhyF --- .github/workflows/ci.yml | 15 +++++++++++++++ src/SignsOfAI.Cli/BuildInfo.cs | 32 ++++++++++++++++++++++++++++++++ src/SignsOfAI.Cli/Program.cs | 4 +++- 3 files changed, 50 insertions(+), 1 deletion(-) create mode 100644 src/SignsOfAI.Cli/BuildInfo.cs diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 18d61f7..bb6e3a6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -45,6 +45,21 @@ jobs: - name: Test boot script run: node --test tests/boot/boot.test.mjs + # `signsofai --version` reported 0.1.0 for seven releases, because the number was restated in + # Program.cs instead of read from the build. Anyone checking whether they had a fix was told + # they were on the first release ever published. This runs the tool that was just built and + # compares what it says against the version the csproj packs, so the two cannot drift again. + - name: The CLI reports the version it was built as + run: | + want=$(grep -oPm1 '(?<=)[^<]+' src/SignsOfAI.Cli/SignsOfAI.Cli.csproj) + got=$(dotnet run --project src/SignsOfAI.Cli -c Release --no-build -- --version) + echo "csproj packs $want; the tool reports $got" + if [ "$want" != "$got" ]; then + echo "::error::signsofai --version says $got but this build is $want." + echo "Program.cs must read the version from the assembly, never restate it." + exit 1 + fi + # The desktop app is WPF, so it needs a Windows runner and it is not in SignsOfAI.slnx — see the # comment at the top of that file. Its own job keeps the build above on Linux, where it stays fast # for the translation PRs that are the reason this workflow exists. diff --git a/src/SignsOfAI.Cli/BuildInfo.cs b/src/SignsOfAI.Cli/BuildInfo.cs new file mode 100644 index 0000000..6d79de2 --- /dev/null +++ b/src/SignsOfAI.Cli/BuildInfo.cs @@ -0,0 +1,32 @@ +using System.Reflection; + +namespace SignsOfAI.Cli; + +/// +/// The version this build actually is, taken from the assembly the compiler stamped from +/// <Version> in the csproj. Restating it in source is how `--version` came to report 0.1.0 +/// while the published package was 0.6.0 — seven releases of a tool telling people the wrong +/// answer to the one question they ask when a fix does not seem to be there. +/// +public static class BuildInfo +{ + public static string Version { get; } = Read(); + + private static string Read() + { + var assembly = typeof(BuildInfo).Assembly; + + // InformationalVersion carries the full "0.7.0+" when SourceLink is on; the build + // metadata after '+' is not part of the version people are asking about. + string? informational = assembly + .GetCustomAttribute()?.InformationalVersion; + if (!string.IsNullOrWhiteSpace(informational)) + { + int plus = informational.IndexOf('+'); + return plus < 0 ? informational : informational[..plus]; + } + + // A version with a trailing ".0" the csproj never wrote is still the truth about this build. + return assembly.GetName().Version?.ToString(3) ?? "unknown"; + } +} diff --git a/src/SignsOfAI.Cli/Program.cs b/src/SignsOfAI.Cli/Program.cs index 767f0f4..3b1d54e 100644 --- a/src/SignsOfAI.Cli/Program.cs +++ b/src/SignsOfAI.Cli/Program.cs @@ -10,7 +10,9 @@ using SignsOfAI.Core.Rules; // ── signsofai: lint prose for the signs of AI writing ──────────────────────── -const string Version = "0.1.0"; +// Read from the assembly, never restated here: a constant went seven releases saying 0.1.0 while +// the package said 0.6.0, so anyone checking whether they had a fix was told they did not. +string Version = SignsOfAI.Cli.BuildInfo.Version; // Emit UTF-8 so accents, · separators and glyphs render on Windows consoles too. try { Console.OutputEncoding = System.Text.Encoding.UTF8; } catch { /* redirected / unsupported */ }