From 756421174d78ff9cf762a5d190d0e8bfbf682d46 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 13 Jul 2026 16:41:21 +0000 Subject: [PATCH 1/2] feat(gendoc): log the runtime the worker bound to The worker rolls forward independently of the launching tool (RollForward= LatestMajor), so the runtime it documents a target on can differ from the CLI's and was not visible anywhere. Emit a one-line banner built from RuntimeInformation.FrameworkDescription. It goes to stdout when the result is written to a file (stdout then carries no data and the host surfaces it as an 'info' diagnostic) and to stderr in the stdout-JSON mode so the result stays pure. The preview canary reads this banner back to show which runtime fce actually used. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_015HeXL6s4yGMAgZitfWijs1 --- FirstClassErrors.GenDoc.Worker/Program.cs | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/FirstClassErrors.GenDoc.Worker/Program.cs b/FirstClassErrors.GenDoc.Worker/Program.cs index 2af528f..7c10557 100644 --- a/FirstClassErrors.GenDoc.Worker/Program.cs +++ b/FirstClassErrors.GenDoc.Worker/Program.cs @@ -3,6 +3,7 @@ using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Reflection; +using System.Runtime.InteropServices; using System.Text.Json; using System.Text.Json.Serialization; @@ -17,7 +18,10 @@ // The worker is meant to be launched by the generator against the target's own dependency closure // (dotnet exec --depsfile .deps.json ... worker.dll .dll), so it binds to the target's // FirstClassErrors version and starts from a fresh static registry. It writes the ErrorDocumentationExtractionResult -// as JSON to the output file when provided, otherwise to stdout; diagnostics and fatal errors go to stderr. +// as JSON to the output file when provided, otherwise to stdout. Fatal errors go to stderr. It also logs a one-line +// runtime banner (the framework it actually bound to): on stdout when the result goes to a file — stdout then carries +// no data and the host surfaces the banner as an 'info' diagnostic — and on stderr in the stdout-JSON mode so the +// result stays pure. // // When --culture is given, the extraction runs under that culture, so documentation factories that read localized // resources produce their text in that language. @@ -53,6 +57,17 @@ } try { + // Report the runtime this worker actually bound to. Its runtimeconfig rolls forward independently of the + // launching tool (RollForward=LatestMajor), so this can differ from the CLI's runtime and is the authoritative + // record of where the target was loaded — which is what the preview canary reads back. See the header note for + // the stdout/stderr split. + string runtimeBanner = $"Documenting '{assemblyPath}' on {RuntimeInformation.FrameworkDescription}."; + if (outputPath is null) { + await Console.Error.WriteLineAsync(runtimeBanner); + } else { + await Console.Out.WriteLineAsync(runtimeBanner); + } + Assembly assembly = LoadTarget(assemblyPath); ErrorDocumentationExtractionResult result = AssemblyErrorDocumentationReader.GetErrorDocumentationFrom(assembly); From f7fb6b7ab87446d1e5ca5c6560cf1ed6800daa21 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 13 Jul 2026 16:41:21 +0000 Subject: [PATCH 2/2] ci: surface the .NET runtime in the preview canary The canary passed green but never printed which runtime it ran on: dotnet --list-runtimes was consumed by a silent grep, so "ran on the preview" had to be inferred. Print the installed runtimes and the highest major, skip neutrally unless a runtime newer than the .NET 10 build SDK is present, and name that major in the success line. With the worker's runtime banner (via --verbose), the log now shows the preview version instead of leaving it to inference. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_015HeXL6s4yGMAgZitfWijs1 --- .github/workflows/canary.yml | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/.github/workflows/canary.yml b/.github/workflows/canary.yml index 3dda2ce..c73378a 100644 --- a/.github/workflows/canary.yml +++ b/.github/workflows/canary.yml @@ -76,9 +76,11 @@ jobs: # so both processes select the highest installed major rather than staying on a stable one; # * DOTNET_ROLL_FORWARD_TO_PRERELEASE=1 lets a stable net8 app bind a *prerelease* runtime, which # roll-forward refuses by default. - # A guard first confirms a newer major than the build SDK is actually installed, so the canary never - # false-passes by silently running on .NET 10. A regression in the preview runtime's roll-forward behaviour - # then turns this step red, and the scheduled run notifies the maintainer. + # The step PRINTS the installed runtimes and the highest major first, so the log shows the preview it is about + # to exercise instead of leaving it to be inferred. It then guards: only a runtime newer than the .NET 10 build + # SDK proves anything, so if the preview install did not yield one the run skips neutrally rather than + # false-passing on .NET 10. fce runs with --verbose, so the worker additionally logs the exact runtime it bound + # to (its "Documenting '…' on .NET ." banner). - name: Generate documentation on the preview runtime if: steps.preview.outcome == 'success' env: @@ -86,8 +88,12 @@ jobs: DOTNET_ROLL_FORWARD_TO_PRERELEASE: '1' run: | set -euo pipefail - if ! dotnet --list-runtimes | grep -Eq 'Microsoft\.NETCore\.App (1[1-9]|[2-9][0-9])\.'; then - echo "::notice::the installed 'preview' is not a newer major than the build SDK; skipping this run" + echo "Installed .NET runtimes:" + dotnet --list-runtimes + newest="$(dotnet --list-runtimes | sed -nE 's/^Microsoft\.NETCore\.App ([0-9]+)\..*/\1/p' | sort -n | tail -1)" + echo "Highest installed .NET major: ${newest:-none}" + if [ "${newest:-0}" -le 10 ]; then + echo "::notice::no runtime newer than the .NET 10 build SDK is installed; skipping this run" exit 0 fi dotnet FirstClassErrors.Cli/bin/Release/net8.0/fce.dll generate \ @@ -99,4 +105,4 @@ jobs: cat canary-catalog.json exit 1 fi - echo "ok: the net8 fce and worker documented a net8 target on the .NET preview runtime" + echo "ok: the net8 fce and worker documented a net8 target on the .NET ${newest} preview runtime"