From 425e9ba81a117c97a5a9326b293f3db129070198 Mon Sep 17 00:00:00 2001 From: Tyler Kron Date: Sat, 23 May 2026 17:53:00 -0600 Subject: [PATCH 1/2] chore: pre-release polish (filename, versioned user-agent, SD parser pragmas) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Three small cleanups bundled together: 1. Rename TestMessage.cs to TextMessage.cs to match its class — the file contained `class TextMessage` (a production message type), not test code. 2. Derive GitHubFirmwareDownloadService user-agent from the assembly version instead of a hardcoded "1.0", so GitHub rate-limit/abuse fingerprints move with each release. `const` becomes `static readonly` since the interpolation can't be evaluated at compile time. 3. Replace the no-op `await Task.CompletedTask;` shim in the SD parser IAsyncEnumerable iterators with `#pragma warning disable CS1998`. These methods need `async` to allow `yield return`, but have no real awaits; the pragma documents that intent explicitly and survives TreatWarningsAsErrors. Applied to the three production parser methods and the two `EmptySamples()` helpers in Json/Csv parsers for consistency. Closes #223 Co-Authored-By: Claude Opus 4.7 (1M context) --- .../Messages/{TestMessage.cs => TextMessage.cs} | 0 src/Daqifi.Core/Device/SdCard/SdCardCsvFileParser.cs | 7 ++++--- src/Daqifi.Core/Device/SdCard/SdCardFileParser.cs | 4 ++-- src/Daqifi.Core/Device/SdCard/SdCardJsonFileParser.cs | 7 ++++--- src/Daqifi.Core/Firmware/GitHubFirmwareDownloadService.cs | 3 ++- 5 files changed, 12 insertions(+), 9 deletions(-) rename src/Daqifi.Core/Communication/Messages/{TestMessage.cs => TextMessage.cs} (100%) diff --git a/src/Daqifi.Core/Communication/Messages/TestMessage.cs b/src/Daqifi.Core/Communication/Messages/TextMessage.cs similarity index 100% rename from src/Daqifi.Core/Communication/Messages/TestMessage.cs rename to src/Daqifi.Core/Communication/Messages/TextMessage.cs diff --git a/src/Daqifi.Core/Device/SdCard/SdCardCsvFileParser.cs b/src/Daqifi.Core/Device/SdCard/SdCardCsvFileParser.cs index 8c3c370..bb2d212 100644 --- a/src/Daqifi.Core/Device/SdCard/SdCardCsvFileParser.cs +++ b/src/Daqifi.Core/Device/SdCard/SdCardCsvFileParser.cs @@ -249,6 +249,7 @@ private static int FindDataStartIndex(List lines) return lines.Count; // No data found } +#pragma warning disable CS1998 // Async iterator: yield return requires async; method has no real awaits. private static async IAsyncEnumerable ParseCsvLines( List lines, int dataStartIndex, @@ -316,9 +317,8 @@ private static async IAsyncEnumerable ParseCsvLines( // Final progress report progress?.Report(new SdCardParseProgress(bytesRead, totalBytes, linesProcessed)); - - await Task.CompletedTask; // keep the method async-compatible } +#pragma warning restore CS1998 /// /// Parses a firmware CSV data row with interleaved per-channel timestamp/value pairs. @@ -472,9 +472,10 @@ private static long ComputeTickDelta(uint previous, uint current) return (long)(uint.MaxValue - previous) + current + 1; } +#pragma warning disable CS1998 // Async iterator: yield break requires async; no real awaits. private static async IAsyncEnumerable EmptySamples() { - await Task.CompletedTask; yield break; } +#pragma warning restore CS1998 } diff --git a/src/Daqifi.Core/Device/SdCard/SdCardFileParser.cs b/src/Daqifi.Core/Device/SdCard/SdCardFileParser.cs index 85bc8b1..c813543 100644 --- a/src/Daqifi.Core/Device/SdCard/SdCardFileParser.cs +++ b/src/Daqifi.Core/Device/SdCard/SdCardFileParser.cs @@ -210,6 +210,7 @@ private static async Task> ReadAllMessagesAsync( return messages; } +#pragma warning disable CS1998 // Async iterator: yield return requires async; method has no real awaits. /// /// Produces samples from the parsed messages. /// @@ -327,9 +328,8 @@ private static async IAsyncEnumerable ProduceSamples( yield return new SdCardLogEntry(timestamp, analogValues, digitalData, analogTimestamps); } - - await Task.CompletedTask; // keep the method async-compatible } +#pragma warning restore CS1998 /// /// Scales raw ADC integer values using calibration parameters from the device config. diff --git a/src/Daqifi.Core/Device/SdCard/SdCardJsonFileParser.cs b/src/Daqifi.Core/Device/SdCard/SdCardJsonFileParser.cs index a6206d4..3f2b6a7 100644 --- a/src/Daqifi.Core/Device/SdCard/SdCardJsonFileParser.cs +++ b/src/Daqifi.Core/Device/SdCard/SdCardJsonFileParser.cs @@ -98,6 +98,7 @@ public async Task ParseFileAsync( return await ParseAsync(fileStream, Path.GetFileName(filePath), options, ct); } +#pragma warning disable CS1998 // Async iterator: yield return requires async; method has no real awaits. private static async IAsyncEnumerable ParseJsonLines( List lines, SdCardDeviceConfiguration config, @@ -162,9 +163,8 @@ private static async IAsyncEnumerable ParseJsonLines( // Final progress report progress?.Report(new SdCardParseProgress(bytesRead, totalBytes, linesProcessed)); - - await Task.CompletedTask; // keep the method async-compatible } +#pragma warning restore CS1998 private static (uint timestamp, IReadOnlyList analog, uint digital)? TryParseJsonLine(string line) { @@ -332,9 +332,10 @@ private static long ComputeTickDelta(uint previous, uint current) return (long)(uint.MaxValue - previous) + current + 1; } +#pragma warning disable CS1998 // Async iterator: yield break requires async; no real awaits. private static async IAsyncEnumerable EmptySamples() { - await Task.CompletedTask; yield break; } +#pragma warning restore CS1998 } diff --git a/src/Daqifi.Core/Firmware/GitHubFirmwareDownloadService.cs b/src/Daqifi.Core/Firmware/GitHubFirmwareDownloadService.cs index 7744e2c..f594ef3 100644 --- a/src/Daqifi.Core/Firmware/GitHubFirmwareDownloadService.cs +++ b/src/Daqifi.Core/Firmware/GitHubFirmwareDownloadService.cs @@ -8,7 +8,8 @@ namespace Daqifi.Core.Firmware; /// public sealed class GitHubFirmwareDownloadService : IFirmwareDownloadService { - private const string DEFAULT_USER_AGENT = "DaqifiFirmwareUpdater/1.0"; + private static readonly string DEFAULT_USER_AGENT = + $"DaqifiFirmwareUpdater/{typeof(GitHubFirmwareDownloadService).Assembly.GetName().Version}"; private const int DOWNLOAD_BUFFER_SIZE = 8192; private readonly HttpClient _httpClient; From de53f6f34ac05acaeb8b6770d54e5a780077a6da Mon Sep 17 00:00:00 2001 From: Tyler Kron Date: Sat, 23 May 2026 17:59:34 -0600 Subject: [PATCH 2/2] fix(firmware): use InformationalVersion for user-agent to preserve SemVer suffix Per Qodo review on #227: `Assembly.GetName().Version` is numeric-only ("1.0.0.0") and truncates SemVer prerelease suffixes. The release workflow passes `/p:Version=1.0.0-beta.1` which sets `AssemblyInformationalVersion` but writes only `1.0.0.0` to `AssemblyVersion`, so prerelease builds would have been indistinguishable from stable ones in GitHub API traffic. Switch to `AssemblyInformationalVersionAttribute.InformationalVersion` with `AssemblyName.Version` as a fallback. Both are RFC 7231 user-agent token compliant (the `+` SourceLink suffix is allowed in product-version). Co-Authored-By: Claude Opus 4.7 (1M context) --- .../Firmware/GitHubFirmwareDownloadService.cs | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/Daqifi.Core/Firmware/GitHubFirmwareDownloadService.cs b/src/Daqifi.Core/Firmware/GitHubFirmwareDownloadService.cs index f594ef3..3dd797d 100644 --- a/src/Daqifi.Core/Firmware/GitHubFirmwareDownloadService.cs +++ b/src/Daqifi.Core/Firmware/GitHubFirmwareDownloadService.cs @@ -1,4 +1,5 @@ using System.IO.Compression; +using System.Reflection; using System.Text.Json; namespace Daqifi.Core.Firmware; @@ -8,10 +9,21 @@ namespace Daqifi.Core.Firmware; /// public sealed class GitHubFirmwareDownloadService : IFirmwareDownloadService { - private static readonly string DEFAULT_USER_AGENT = - $"DaqifiFirmwareUpdater/{typeof(GitHubFirmwareDownloadService).Assembly.GetName().Version}"; + private static readonly string DEFAULT_USER_AGENT = BuildDefaultUserAgent(); private const int DOWNLOAD_BUFFER_SIZE = 8192; + private static string BuildDefaultUserAgent() + { + // Prefer InformationalVersion so prerelease SemVer suffixes (e.g. "1.0.0-beta.1") + // survive into GitHub API traffic for rate-limit/abuse investigations. + // AssemblyVersion is numeric-only and would truncate them. + var assembly = typeof(GitHubFirmwareDownloadService).Assembly; + var version = assembly.GetCustomAttribute()?.InformationalVersion + ?? assembly.GetName().Version?.ToString() + ?? "unknown"; + return $"DaqifiFirmwareUpdater/{version}"; + } + private readonly HttpClient _httpClient; private readonly string _firmwareRepoApiUrl; private readonly string _wifiRepoApiUrl;