From 81414b13e3e5d2b9319e879490d45f2682669e1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Desbiens?= Date: Wed, 26 Aug 2026 15:58:13 -0400 Subject: [PATCH 1/6] Revived the Windows workflows, which had reached no runner since 2025 The four GUIX Studio workflows requested `runs-on: windows-2019`, an image GitHub retired on 2025-06-30. Nothing can match a retired label, so every run queued for the full 24 hours and was then cancelled without ever starting a job: run 28477318708 created 2026-06-30T21:33:40Z cancelled 2026-07-01T21:33:41Z Every run of these workflows since 2025-09-29 has that same created-plus-24h-cancelled shape. The Studio demo, demo compile, view and MSIX package tests have gated nothing for about a year, and a manual workflow_dispatch on 2026-08-25 queued the same way. Three more defects were in the path behind that one, so fixing the image alone would not have produced a green run. - actions/upload-artifact was pinned at v3.1.3 in all four workflows. GitHub began auto-failing every request that used v3 on 2025-01-30, and both upload steps run under `if: success() || failure()`, so every run would have ended red even with the tests passing. - The scripts hard-coded a Visual Studio edition path. build_guix.cmd, test_studio_demo.cmd, test_studio_demo_compile.cmd and test_studio_view.cmd all call VS 2022 *Enterprise*, which no developer machine has, and build_guix_studio.cmd calls VS 2022 *Community*, which no GitHub runner has. So the demo test's build step would have failed on the first line. All five now locate the installation with vswhere, matching what build_guix_studio_msix_package.cmd already did, and check the result instead of assuming the call succeeded. Verified on a Community install, where the Enterprise path does not exist. - studio_msix_package.yml uploaded guix_studio/build/vs_2019/msix_package_project/AppPackages. That directory has not existed since the solution moved to vs_2022, which is where build_guix_studio_msix_package.cmd builds, so the artifact was always empty. Every action reference is now a 40-character commit SHA with the version in a trailing comment, following the pattern eclipse-threadx/threadx adopted in August 2026. A tag can be repointed at any commit; a SHA cannot, which is what makes "which code ran in our CI" answerable from the repository. Versions moved with the pinning: actions/checkout v4 -> v7.0.1 actions/upload-artifact v3.1.3 -> v7.0.1 EnricoMi/publish-unit-test-result-action v2 -> v2.24.0 Compatibility was checked against each new action.yml rather than assumed, for every input these workflows actually pass: checkout keeps `submodules`; upload-artifact keeps `name` and `path`, and the one upload per run means the v4 rule against uploading a name twice does not bite; the publish action keeps `check_name` and `files`, and the `composite` variant still exists at v2.24.0, which is the one a Windows runner needs. All three tags were confirmed to resolve to the SHAs pinned here, and all three are the current latest. The runner image is pinned rather than tracking windows-latest, on the same reasoning threadx applies to ubuntu-24.04: which image the build ran on should be a reviewable commit, not something that changes underneath it. Floating would have hidden this failure differently rather than preventing it. Also removed the dead `C:\Program Files\Python36` PATH lines. No supported runner image has shipped that Python for years, python is already on PATH there, and the lines embedded literal quote characters into PATH. The trigger branches are deliberately left alone in this commit. These workflows fire on master only, so they still gate no pull request to dev -- the same defect threadx fixed in its own suites. That wants a dispatch run to go green first, on evidence rather than hope, and is a separate change. Assisted-by: Claude Code (Opus 5) Co-Authored-By: Claude Opus 5 (1M context) --- .github/workflows/studio_demo_test.yml | 18 +++++++++++---- .../workflows/studio_demo_test_compile.yml | 18 +++++++++++---- .github/workflows/studio_msix_package.yml | 18 +++++++++++---- .github/workflows/studio_view_test.yml | 18 +++++++++++---- scripts/build_guix.cmd | 23 +++++++++++++++---- scripts/build_guix_studio.cmd | 23 +++++++++++++++---- scripts/test_studio_demo.cmd | 23 +++++++++++++++---- scripts/test_studio_demo_compile.cmd | 23 +++++++++++++++---- scripts/test_studio_view.cmd | 23 +++++++++++++++---- 9 files changed, 146 insertions(+), 41 deletions(-) diff --git a/.github/workflows/studio_demo_test.yml b/.github/workflows/studio_demo_test.yml index 1acc41033..fcc9baee2 100644 --- a/.github/workflows/studio_demo_test.yml +++ b/.github/workflows/studio_demo_test.yml @@ -6,6 +6,7 @@ # https://opensource.org/licenses/MIT. # # SPDX-License-Identifier: MIT +# Some portions generated by Claude Code (Opus 5). # This is a basic workflow that is manually triggered @@ -31,12 +32,21 @@ jobs: pull-requests: write # The type of runner that the job will run on - runs-on: windows-2019 + # Pinned deliberately rather than windows-latest: the image this job + # needs has to be a reviewable commit, not something that changes + # underneath the build. windows-2019 sat here until 2026-08-26, more + # than a year after GitHub retired that image, so every run queued for + # 24 hours and was then cancelled without ever reaching a runner. + runs-on: windows-2022 # Steps represent a sequence of tasks that will be executed as part of the job steps: + # Actions are pinned to a commit SHA, with the version in the trailing + # comment. A tag can be moved; a SHA cannot, so this is what makes "which + # code ran in CI" answerable from the repository. Dependabot moves these + # pins and rewrites the comment with them -- see .github/dependabot.yml. - name: Check out the repository - uses: actions/checkout@v4 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: submodules: true @@ -47,7 +57,7 @@ jobs: run: scripts\test_studio_demo.cmd - name: Publish Test Results - uses: EnricoMi/publish-unit-test-result-action/composite@v2 + uses: EnricoMi/publish-unit-test-result-action/composite@d0a4676d0e0b938bc201470d88276b7c74c712b3 # v2.24.0 if: always() with: check_name: Test Results GUIX Studio Demo @@ -56,7 +66,7 @@ jobs: - name: Upload Test Results if: success() || failure() - uses: actions/upload-artifact@v3.1.3 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: test_reports path: | diff --git a/.github/workflows/studio_demo_test_compile.yml b/.github/workflows/studio_demo_test_compile.yml index 897eb3fcd..59c2ea995 100644 --- a/.github/workflows/studio_demo_test_compile.yml +++ b/.github/workflows/studio_demo_test_compile.yml @@ -6,6 +6,7 @@ # https://opensource.org/licenses/MIT. # # SPDX-License-Identifier: MIT +# Some portions generated by Claude Code (Opus 5). # This is a basic workflow that is manually triggered @@ -31,12 +32,21 @@ jobs: pull-requests: write # The type of runner that the job will run on - runs-on: windows-2019 + # Pinned deliberately rather than windows-latest: the image this job + # needs has to be a reviewable commit, not something that changes + # underneath the build. windows-2019 sat here until 2026-08-26, more + # than a year after GitHub retired that image, so every run queued for + # 24 hours and was then cancelled without ever reaching a runner. + runs-on: windows-2022 # Steps represent a sequence of tasks that will be executed as part of the job steps: + # Actions are pinned to a commit SHA, with the version in the trailing + # comment. A tag can be moved; a SHA cannot, so this is what makes "which + # code ran in CI" answerable from the repository. Dependabot moves these + # pins and rewrites the comment with them -- see .github/dependabot.yml. - name: Check out the repository - uses: actions/checkout@v4 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: submodules: true @@ -47,7 +57,7 @@ jobs: run: scripts\test_studio_demo_compile.cmd - name: Publish Test Results - uses: EnricoMi/publish-unit-test-result-action/composite@v2 + uses: EnricoMi/publish-unit-test-result-action/composite@d0a4676d0e0b938bc201470d88276b7c74c712b3 # v2.24.0 if: always() with: check_name: Test Results GUIX Studio Demo Compile @@ -56,7 +66,7 @@ jobs: - name: Upload Test Results if: success() || failure() - uses: actions/upload-artifact@v3.1.3 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: test_reports path: | diff --git a/.github/workflows/studio_msix_package.yml b/.github/workflows/studio_msix_package.yml index 2ff833560..cce0d49da 100644 --- a/.github/workflows/studio_msix_package.yml +++ b/.github/workflows/studio_msix_package.yml @@ -6,6 +6,7 @@ # https://opensource.org/licenses/MIT. # # SPDX-License-Identifier: MIT +# Some portions generated by Claude Code (Opus 5). # This is a basic workflow that is manually triggered @@ -26,12 +27,21 @@ jobs: pull-requests: write # The type of runner that the job will run on - runs-on: windows-2019 + # Pinned deliberately rather than windows-latest: the image this job + # needs has to be a reviewable commit, not something that changes + # underneath the build. windows-2019 sat here until 2026-08-26, more + # than a year after GitHub retired that image, so every run queued for + # 24 hours and was then cancelled without ever reaching a runner. + runs-on: windows-2022 # Steps represent a sequence of tasks that will be executed as part of the job steps: + # Actions are pinned to a commit SHA, with the version in the trailing + # comment. A tag can be moved; a SHA cannot, so this is what makes "which + # code ran in CI" answerable from the repository. Dependabot moves these + # pins and rewrites the comment with them -- see .github/dependabot.yml. - name: Check out the repository - uses: actions/checkout@v4 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: submodules: true @@ -39,9 +49,9 @@ jobs: run: scripts/build_guix_studio_msix_package.cmd - name: Upload GUIX Studio package upload file - uses: actions/upload-artifact@v3.1.3 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: GUIXStudioPackages - path: guix_studio/build/vs_2019/msix_package_project/AppPackages + path: guix_studio/build/vs_2022/msix_package_project/AppPackages \ No newline at end of file diff --git a/.github/workflows/studio_view_test.yml b/.github/workflows/studio_view_test.yml index dac9be92d..cc4b2cb2d 100644 --- a/.github/workflows/studio_view_test.yml +++ b/.github/workflows/studio_view_test.yml @@ -6,6 +6,7 @@ # https://opensource.org/licenses/MIT. # # SPDX-License-Identifier: MIT +# Some portions generated by Claude Code (Opus 5). # This is a basic workflow that is manually triggered @@ -31,12 +32,21 @@ jobs: pull-requests: write # The type of runner that the job will run on - runs-on: windows-2019 + # Pinned deliberately rather than windows-latest: the image this job + # needs has to be a reviewable commit, not something that changes + # underneath the build. windows-2019 sat here until 2026-08-26, more + # than a year after GitHub retired that image, so every run queued for + # 24 hours and was then cancelled without ever reaching a runner. + runs-on: windows-2022 # Steps represent a sequence of tasks that will be executed as part of the job steps: + # Actions are pinned to a commit SHA, with the version in the trailing + # comment. A tag can be moved; a SHA cannot, so this is what makes "which + # code ran in CI" answerable from the repository. Dependabot moves these + # pins and rewrites the comment with them -- see .github/dependabot.yml. - name: Check out the repository - uses: actions/checkout@v4 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: submodules: true @@ -47,7 +57,7 @@ jobs: run: scripts\test_studio_view.cmd - name: Publish Test Results - uses: EnricoMi/publish-unit-test-result-action/composite@v2 + uses: EnricoMi/publish-unit-test-result-action/composite@d0a4676d0e0b938bc201470d88276b7c74c712b3 # v2.24.0 if: always() with: check_name: Test Results GUIX Studio View @@ -56,7 +66,7 @@ jobs: - name: Upload Test Results if: success() || failure() - uses: actions/upload-artifact@v3.1.3 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: test_reports path: | diff --git a/scripts/build_guix.cmd b/scripts/build_guix.cmd index 205723baa..647d4ca44 100644 --- a/scripts/build_guix.cmd +++ b/scripts/build_guix.cmd @@ -7,13 +7,26 @@ @rem @rem SPDX-License-Identifier: MIT @rem Some portions generated by Codex (OpenAI GPT-5.5). +@rem Some portions generated by Claude Code (Opus 5). -rem Initialize the developer environment just like a developer box. Note that 'call' keyword that ensures that the script does not exist after -rem calling the other batch file. -call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\Common7\Tools\VsDevCmd.bat" -arch=amd64 -host_arch=amd64 +rem Initialize the developer environment just like a developer box. The Visual +rem Studio edition differs between a developer machine and a GitHub runner, so +rem locate the installation with vswhere rather than assuming an edition path. +rem Note the 'call' keyword, which ensures that this script does not exit when +rem the other batch file returns. +set "VSINSTALL=" +set "VSWHERE=%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe" +if exist "%VSWHERE%" ( + for /f "usebackq tokens=*" %%i in (`"%VSWHERE%" -latest -products * -requires Microsoft.Component.MSBuild -property installationPath`) do set "VSINSTALL=%%i" +) -rem Set Python path -SET PATH=%PATH%;"C:\Program Files\Python36";"C:\Program Files\Python36\scripts" +if not defined VSINSTALL ( + echo Visual Studio 2022 with MSBuild was not found. + exit /B 1 +) + +call "%VSINSTALL%\Common7\Tools\VsDevCmd.bat" -arch=amd64 -host_arch=amd64 +if ERRORLEVEL 1 exit /B %ERRORLEVEL% rem Save working directory so that we can restore it back after building everything. This will make developers happy and then rem switch to the folder this script resides in. Don't assume absolute paths because on the build host and on the dev host the locations may be different. diff --git a/scripts/build_guix_studio.cmd b/scripts/build_guix_studio.cmd index 6bebc2c7d..ac678152d 100644 --- a/scripts/build_guix_studio.cmd +++ b/scripts/build_guix_studio.cmd @@ -6,15 +6,28 @@ @rem https://opensource.org/licenses/MIT. @rem @rem SPDX-License-Identifier: MIT +@rem Some portions generated by Claude Code (Opus 5). @echo off -rem Initialize the developer environment just like a developer box. Note that 'call' keyword that ensures that the script does not exist after -rem calling the other batch file. -call "C:\Program Files\Microsoft Visual Studio\2022\Community\Common7\Tools\VsDevCmd.bat" -arch=amd64 -host_arch=amd64 -winsdk=10.0.22621.0 +rem Initialize the developer environment just like a developer box. The Visual +rem Studio edition differs between a developer machine and a GitHub runner, so +rem locate the installation with vswhere rather than assuming an edition path. +rem Note the 'call' keyword, which ensures that this script does not exit when +rem the other batch file returns. +set "VSINSTALL=" +set "VSWHERE=%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe" +if exist "%VSWHERE%" ( + for /f "usebackq tokens=*" %%i in (`"%VSWHERE%" -latest -products * -requires Microsoft.Component.MSBuild -property installationPath`) do set "VSINSTALL=%%i" +) -rem Set Python path. Not needed if installed with WinGet. -rem SET PATH=%PATH%;"C:\Program Files\Python36";"C:\Program Files\Python36\scripts" +if not defined VSINSTALL ( + echo Visual Studio 2022 with MSBuild was not found. + exit /B 1 +) + +call "%VSINSTALL%\Common7\Tools\VsDevCmd.bat" -arch=amd64 -host_arch=amd64 -winsdk=10.0.22621.0 +if ERRORLEVEL 1 exit /B %ERRORLEVEL% rem Save working directory so that we can restore it back after building everything. This will make developers happy and then rem switch to the folder this script resides in. Don't assume absolute paths because on the build host and on the dev host the locations may be different. diff --git a/scripts/test_studio_demo.cmd b/scripts/test_studio_demo.cmd index 3143f485c..4a6bbca64 100644 --- a/scripts/test_studio_demo.cmd +++ b/scripts/test_studio_demo.cmd @@ -7,13 +7,26 @@ @rem @rem SPDX-License-Identifier: MIT @rem Some portions generated by Codex (OpenAI GPT-5.5). +@rem Some portions generated by Claude Code (Opus 5). -rem Initialize the developer environment just like a developer box. Note that 'call' keyword that ensures that the script does not exist after -rem calling the other batch file. -call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\Common7\Tools\VsDevCmd.bat" -arch=amd64 -host_arch=amd64 +rem Initialize the developer environment just like a developer box. The Visual +rem Studio edition differs between a developer machine and a GitHub runner, so +rem locate the installation with vswhere rather than assuming an edition path. +rem Note the 'call' keyword, which ensures that this script does not exit when +rem the other batch file returns. +set "VSINSTALL=" +set "VSWHERE=%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe" +if exist "%VSWHERE%" ( + for /f "usebackq tokens=*" %%i in (`"%VSWHERE%" -latest -products * -requires Microsoft.Component.MSBuild -property installationPath`) do set "VSINSTALL=%%i" +) -rem Set Python path -SET PATH=%PATH%;"C:\Program Files\Python36";"C:\Program Files\Python36\scripts" +if not defined VSINSTALL ( + echo Visual Studio 2022 with MSBuild was not found. + exit /B 1 +) + +call "%VSINSTALL%\Common7\Tools\VsDevCmd.bat" -arch=amd64 -host_arch=amd64 +if ERRORLEVEL 1 exit /B %ERRORLEVEL% rem Save working directory so that we can restore it back after building everything. This will make developers happy and then rem switch to the folder this script resides in. Don't assume absolute paths because on the build host and on the dev host the locations may be different. diff --git a/scripts/test_studio_demo_compile.cmd b/scripts/test_studio_demo_compile.cmd index 5a08cf24f..217cff9a1 100644 --- a/scripts/test_studio_demo_compile.cmd +++ b/scripts/test_studio_demo_compile.cmd @@ -7,13 +7,26 @@ @rem @rem SPDX-License-Identifier: MIT @rem Some portions generated by Codex (OpenAI GPT-5.5). +@rem Some portions generated by Claude Code (Opus 5). -rem Initialize the developer environment just like a developer box. Note that 'call' keyword that ensures that the script does not exist after -rem calling the other batch file. -call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\Common7\Tools\VsDevCmd.bat" -arch=amd64 -host_arch=amd64 +rem Initialize the developer environment just like a developer box. The Visual +rem Studio edition differs between a developer machine and a GitHub runner, so +rem locate the installation with vswhere rather than assuming an edition path. +rem Note the 'call' keyword, which ensures that this script does not exit when +rem the other batch file returns. +set "VSINSTALL=" +set "VSWHERE=%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe" +if exist "%VSWHERE%" ( + for /f "usebackq tokens=*" %%i in (`"%VSWHERE%" -latest -products * -requires Microsoft.Component.MSBuild -property installationPath`) do set "VSINSTALL=%%i" +) -rem Set Python path -SET PATH=%PATH%;"C:\Program Files\Python36";"C:\Program Files\Python36\scripts" +if not defined VSINSTALL ( + echo Visual Studio 2022 with MSBuild was not found. + exit /B 1 +) + +call "%VSINSTALL%\Common7\Tools\VsDevCmd.bat" -arch=amd64 -host_arch=amd64 +if ERRORLEVEL 1 exit /B %ERRORLEVEL% rem Save working directory so that we can restore it back after building everything. This will make developers happy and then rem switch to the folder this script resides in. Don't assume absolute paths because on the build host and on the dev host the locations may be different. diff --git a/scripts/test_studio_view.cmd b/scripts/test_studio_view.cmd index fa7724a41..2bcda14b6 100644 --- a/scripts/test_studio_view.cmd +++ b/scripts/test_studio_view.cmd @@ -7,13 +7,26 @@ @rem @rem SPDX-License-Identifier: MIT @rem Some portions generated by Codex (OpenAI GPT-5.5). +@rem Some portions generated by Claude Code (Opus 5). -rem Initialize the developer environment just like a developer box. Note that 'call' keyword that ensures that the script does not exist after -rem calling the other batch file. -call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\Common7\Tools\VsDevCmd.bat" -arch=amd64 -host_arch=amd64 +rem Initialize the developer environment just like a developer box. The Visual +rem Studio edition differs between a developer machine and a GitHub runner, so +rem locate the installation with vswhere rather than assuming an edition path. +rem Note the 'call' keyword, which ensures that this script does not exit when +rem the other batch file returns. +set "VSINSTALL=" +set "VSWHERE=%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe" +if exist "%VSWHERE%" ( + for /f "usebackq tokens=*" %%i in (`"%VSWHERE%" -latest -products * -requires Microsoft.Component.MSBuild -property installationPath`) do set "VSINSTALL=%%i" +) -rem Set Python path -SET PATH=%PATH%;"C:\Program Files\Python36";"C:\Program Files\Python36\scripts" +if not defined VSINSTALL ( + echo Visual Studio 2022 with MSBuild was not found. + exit /B 1 +) + +call "%VSINSTALL%\Common7\Tools\VsDevCmd.bat" -arch=amd64 -host_arch=amd64 +if ERRORLEVEL 1 exit /B %ERRORLEVEL% rem Save working directory so that we can restore it back after building everything. This will make developers happy and then rem switch to the folder this script resides in. Don't assume absolute paths because on the build host and on the dev host the locations may be different. From 231cc3dd76d937df8fd85a5757da55bad81738bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Desbiens?= Date: Wed, 26 Aug 2026 15:58:29 -0400 Subject: [PATCH 2/6] Added the Dependabot configuration the pinned actions need Follow-up to the pinning in the preceding commit. A SHA pin with nothing moving it is worse than a floating tag: it holds CI on whatever was current the day it was written. This repository is the case study for that. Nothing had ever reported that an action moved, so actions/upload-artifact sat at v3.1.3 in all four Windows workflows -- four majors behind, and a version GitHub began auto-failing every request for on 2025-01-30 -- while actions/checkout sat on an unpinned @v4, three majors behind. This adds .github/dependabot.yml: weekly, github-actions only, and closes the reference to that path which the pinning comment in each workflow now makes. Dependabot understands the SHA form and rewrites the trailing version comment together with the pin, so the comment cannot drift away from the SHA it describes. It follows the configuration eclipse-threadx/threadx added in August 2026, with three differences that are specific to this repository and documented in the file: - Only three distinct actions are in use, so the default limit of five would be enough. Ten is set anyway, to match the sibling repositories and to leave room for a wave of majors after a long gap. - There is no .github/CODEOWNERS here, so no reviewer routing exists for Dependabot to honour. Worth adding, but not by this file. - The "dependencies" label does not exist in this repository yet. Dependabot creates it on the first pull request. Two choices worth stating rather than leaving to be rediscovered. target-branch is dev. Dependabot reads this file from the default branch, which is master -- but master is deliberately kept behind dev, and pull requests belong on dev. So this arms on merge without firing: nothing happens until a release merge carries the file to master. Setting target-branch also opts out of Dependabot security updates, which only ever run against the default branch. For this ecosystem the cost is small, since an action advisory arrives as an ordinary bump on the weekly run, but it is a real trade. Patch and minor are grouped into a single pull request, because a queue reviewed one item at a time is a queue that gets ignored -- which is the failure mode this file exists to prevent. Majors stay ungrouped, one pull request each, because every breaking change met in an action here has been a major: upload-artifact v4 stopped allowing an artifact name to be uploaded twice in a run, and v6 requires a runner of 2.327.1 or newer. Dependabot reports drift, not silence. The Windows workflows rotted because they never reached a runner, not because nobody was told, and the runner image fix in the preceding commit is the cure for that half. The cross-repository reusable workflow in regression_test.yml is correctly left alone: it references a branch, so it carries no version to move. Assisted-by: Claude Code (Opus 5) Co-Authored-By: Claude Opus 5 (1M context) --- .github/dependabot.yml | 100 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 100 insertions(+) create mode 100644 .github/dependabot.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 000000000..c34e84e89 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,100 @@ +version: 2 + +# Keeps the pinned action SHAs moving. +# +# Every action reference under .github/workflows is a 40-character commit SHA +# with the version in a trailing comment. A SHA pin *without* this file is worse +# than a floating tag: it freezes CI on whatever was current the day it was +# written. This repository is the case study. Nothing had ever reported that an +# action moved, so actions/upload-artifact sat on v3.1.3 in all four Windows +# workflows -- four majors behind, and a version GitHub began auto-failing on +# 2025-01-30. actions/checkout sat on an unpinned @v4, three majors behind. +# +# Dependabot understands the SHA form and rewrites the trailing version comment +# together with the pin, so the comment cannot drift away from the SHA it +# describes. That is what keeps "which exact code ran in our CI" answerable from +# the repository, which the SBOM and certification work needs on its own. +# +# This follows the pattern set by eclipse-threadx/threadx, which added the same +# configuration in August 2026 after the same drift was measured there. +# +# What this does not fix: it reports drift, not silence. A workflow that never +# triggers rots unnoticed no matter what is pinned in it, and this repository had +# that failure in its more severe form -- the four Windows workflows requested +# runs-on: windows-2019 for more than a year after GitHub retired that image, so +# every run queued for 24 hours and was cancelled without reaching a runner. No +# amount of pinning would have said so. The runner image fix is a separate +# change; this file is the drift half only. +# +# There is no entry for any other ecosystem, and that is a decision rather than +# an oversight: the project forbids external dependencies and there are no +# submodules. The one pinned toolchain input -- the Windows SDK version passed +# to VsDevCmd in scripts/build_guix_studio.cmd -- lives in a batch file that no +# Dependabot ecosystem can parse. That pin moves by hand. +updates: + - package-ecosystem: "github-actions" + # "/" is the only accepted value for this ecosystem; it covers + # .github/workflows and .github/actions. The cross-repository reusable + # workflow in regression_test.yml + # (eclipse-threadx/threadx/.github/workflows/regression_template.yml@master) + # is correctly left alone: it references a branch, not a version, so there + # is nothing for Dependabot to move. Tracking that branch is deliberate -- + # it is first-party, in the same organisation, and it means this repository + # picks up harness fixes without a bump here. + directory: "/" + + schedule: + interval: "weekly" + day: "monday" + time: "06:00" + timezone: "Etc/UTC" + + # Dependabot reads this file from the repository's DEFAULT branch, which is + # master. But master is deliberately kept behind dev, and pull requests + # belong on dev. target-branch sends the pull requests to dev and makes + # Dependabot read the workflows it is updating from dev as well. + # + # The consequence to plan for: landing this file on dev arms it, it does not + # fire it. Nothing happens until a release merge carries it to master. + # + # Setting target-branch also opts out of Dependabot *security* updates, + # which only ever run against the default branch. For this ecosystem the + # cost is small -- an action advisory arrives as an ordinary version bump on + # the weekly run -- but it is a real trade and not a detail to rediscover + # later. + target-branch: "dev" + + groups: + # Patch and minor arrive together in one pull request: they are the + # routine traffic, and reviewing them one at a time is how an update queue + # starts being ignored, which is the failure mode this file exists to + # prevent. Majors stay ungrouped, one pull request each, because every + # breaking change met in an action here has been a major: upload-artifact + # v4 stopped allowing an artifact name to be uploaded twice in a run, and + # v6 requires a runner of 2.327.1 or newer. + actions-minor-and-patch: + patterns: + - "*" + update-types: + - "minor" + - "patch" + + # Only three distinct actions are in use today -- actions/checkout, + # actions/upload-artifact and EnricoMi/publish-unit-test-result-action -- so + # the default limit of five would be enough for now. Ten is set to match the + # sibling repositories and to leave room for a wave of majors after a long + # gap, which is exactly the situation this file is being added into. + open-pull-requests-limit: 10 + + # This repository has no "dependencies" label yet; Dependabot creates it on + # the first pull request. + labels: + - "dependencies" + + # Reviewers are not listed. Unlike eclipse-threadx/threadx this repository + # has no .github/CODEOWNERS, so there is no path routing for Dependabot to + # honour. Adding one is worth doing, but it is not this file's job. + # + # Commit subjects are left at Dependabot's own "Bump x from a to b" wording. + # The project asks for a past-tense subject and still gets one: these pull + # requests are squash-merged, and the subject is set at that point. From a20422b1f08c658fe36937de312eacc28a9210de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Desbiens?= Date: Wed, 26 Aug 2026 16:05:50 -0400 Subject: [PATCH 3/6] Renamed the Studio IMAGE_INFO struct, which the Windows SDK now defines With the Windows workflows reaching a runner again, the Studio build failed immediately on both of them: guix_studio\system_pngs.h(15,8): error C2011: 'IMAGE_INFO': 'struct' type redefinition Windows Kits\10\Include\10.0.26100.0\um\Filter.h(340,16): error C2011: 'IMAGE_INFO': 'struct' type redefinition plus eight C2027 "use of undefined type" errors following from it. guix_studio declared its own two-field `IMAGE_INFO` in the global namespace. A newer Windows SDK added a struct of the same name to um/Filter.h, which arrives through the Windows headers the MFC sources already include. SDK 10.0.22621.0 does not define it; 10.0.26100.0 does. This was latent rather than new. studiox.vcxproj sets `10.0`, the MSBuild wildcard for "newest installed SDK", so which SDK compiles the Studio depends entirely on the machine. A developer box with 22621 as its newest builds; the runner image, which carries 26100, does not. The collision was simply waiting for whichever came first. Renamed the Studio type to STUDIO_IMAGE_INFO -- 13 references across five files. It is private to the Studio, so nothing outside guix_studio sees the name. Also dropped the `-winsdk=10.0.22621.0` argument that build_guix_studio.cmd passed to VsDevCmd. It never had the effect it looks like it has: the wildcard in the project file governs the SDK the compile actually uses, so the argument only set the shell environment and left MSBuild to pick the newest SDK anyway. Keeping it would suggest the build is pinned to an SDK when it is not. With the collision fixed there is nothing to pin against. Verified by rebuilding the Studio against SDK 10.0.22621.0 locally; the runner will exercise 10.0.26100.0. Assisted-by: Claude Code (Opus 5) Co-Authored-By: Claude Opus 5 (1M context) --- guix_studio/StudioXProject.cpp | 11 ++++++----- guix_studio/resource_gen.cpp | 3 ++- guix_studio/resource_view.h | 5 +++-- guix_studio/system_pngs.cpp | 9 +++++---- guix_studio/system_pngs.h | 3 ++- scripts/build_guix_studio.cmd | 2 +- 6 files changed, 19 insertions(+), 14 deletions(-) diff --git a/guix_studio/StudioXProject.cpp b/guix_studio/StudioXProject.cpp index 527878a9d..517a99537 100644 --- a/guix_studio/StudioXProject.cpp +++ b/guix_studio/StudioXProject.cpp @@ -9,6 +9,7 @@ * SPDX-License-Identifier: MIT **************************************************************************/ // Some portions generated by Codex (OpenAI GPT-5.5). +// Some portions generated by Claude Code (Opus 5). #include "system_pngs.h" @@ -254,10 +255,10 @@ FONT_RECORD DEFAULT_FONT_TABLE[] = { {NULL, -1, NULL} }; -extern IMAGE_INFO _system_png_radio_on; -extern IMAGE_INFO _system_png_radio_off; -extern IMAGE_INFO _system_png_checkbox_on; -extern IMAGE_INFO _system_png_checkbox_off; +extern STUDIO_IMAGE_INFO _system_png_radio_on; +extern STUDIO_IMAGE_INFO _system_png_radio_off; +extern STUDIO_IMAGE_INFO _system_png_checkbox_on; +extern STUDIO_IMAGE_INFO _system_png_checkbox_off; // FIXME: do we want to use hardcoded path? PIXELMAP_RECORD DEFAULT_PIXELMAP_TABLE[] = { @@ -1521,7 +1522,7 @@ BOOL studiox_project::InitializeOnePixelmap(res_info *info, palette_info *theme_ image_reader *pReader = NULL; CString abspath; - IMAGE_INFO *default_image_info = NULL; + STUDIO_IMAGE_INFO *default_image_info = NULL; int frame_count = 1; int frame_id = -1; diff --git a/guix_studio/resource_gen.cpp b/guix_studio/resource_gen.cpp index 5be93459d..cc24e35ab 100644 --- a/guix_studio/resource_gen.cpp +++ b/guix_studio/resource_gen.cpp @@ -9,6 +9,7 @@ * SPDX-License-Identifier: MIT **************************************************************************/ // Some portions generated by Codex (OpenAI GPT-5.5). +// Some portions generated by Claude Code (Opus 5). @@ -4156,7 +4157,7 @@ GX_PIXELMAP* resource_gen::RotatePixelmap(res_info* info, int theme_id, GX_PIXEL image_reader *pReader = NULL; CString abspath; - IMAGE_INFO* default_image_info = NULL; + STUDIO_IMAGE_INFO* default_image_info = NULL; int frame_count = 1; if (info->is_default && info->pathinfo.pathname.IsEmpty()) diff --git a/guix_studio/resource_view.h b/guix_studio/resource_view.h index f0296d399..8c6dcc452 100644 --- a/guix_studio/resource_view.h +++ b/guix_studio/resource_view.h @@ -8,6 +8,7 @@ * * SPDX-License-Identifier: MIT **************************************************************************/ +// Some portions generated by Claude Code (Opus 5). @@ -16,7 +17,7 @@ #include class resource_view_provider; -struct IMAGE_INFO; +struct STUDIO_IMAGE_INFO; struct COLOR_RECORD { char *name; @@ -34,7 +35,7 @@ struct PIXELMAP_RECORD { char *name; int pixelmap_id; BOOL include_alpha; - IMAGE_INFO *image_info; + STUDIO_IMAGE_INFO *image_info; }; struct font_table { diff --git a/guix_studio/system_pngs.cpp b/guix_studio/system_pngs.cpp index f78df6074..b4fd771cb 100644 --- a/guix_studio/system_pngs.cpp +++ b/guix_studio/system_pngs.cpp @@ -8,6 +8,7 @@ * * SPDX-License-Identifier: MIT **************************************************************************/ +// Some portions generated by Claude Code (Opus 5). #include "system_pngs.h" @@ -112,22 +113,22 @@ static unsigned char SYSTEM_PNG_CHECKBOX_OFF_pixelmap_data[519] = 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; -IMAGE_INFO _system_png_radio_on = { +STUDIO_IMAGE_INFO _system_png_radio_on = { SYSTEM_PNG_RADIO_ON_pixelmap_data, sizeof(SYSTEM_PNG_RADIO_ON_pixelmap_data) }; -IMAGE_INFO _system_png_radio_off = { +STUDIO_IMAGE_INFO _system_png_radio_off = { SYSTEM_PNG_RADIO_OFF_pixelmap_data, sizeof(SYSTEM_PNG_RADIO_ON_pixelmap_data) }; -IMAGE_INFO _system_png_checkbox_on = { +STUDIO_IMAGE_INFO _system_png_checkbox_on = { SYSTEM_PNG_CHECKBOX_ON_pixelmap_data, sizeof(SYSTEM_PNG_CHECKBOX_ON_pixelmap_data) }; -IMAGE_INFO _system_png_checkbox_off = { +STUDIO_IMAGE_INFO _system_png_checkbox_off = { SYSTEM_PNG_CHECKBOX_OFF_pixelmap_data, sizeof(SYSTEM_PNG_CHECKBOX_OFF_pixelmap_data) }; \ No newline at end of file diff --git a/guix_studio/system_pngs.h b/guix_studio/system_pngs.h index 910499c09..1b3cff036 100644 --- a/guix_studio/system_pngs.h +++ b/guix_studio/system_pngs.h @@ -8,11 +8,12 @@ * * SPDX-License-Identifier: MIT **************************************************************************/ +// Some portions generated by Claude Code (Opus 5). #ifndef _SYSTEM_PNGS_ #define _SYSTEM_PNGS_ -struct IMAGE_INFO { +struct STUDIO_IMAGE_INFO { unsigned char* data; int data_len; }; diff --git a/scripts/build_guix_studio.cmd b/scripts/build_guix_studio.cmd index ac678152d..600a05ed3 100644 --- a/scripts/build_guix_studio.cmd +++ b/scripts/build_guix_studio.cmd @@ -26,7 +26,7 @@ if not defined VSINSTALL ( exit /B 1 ) -call "%VSINSTALL%\Common7\Tools\VsDevCmd.bat" -arch=amd64 -host_arch=amd64 -winsdk=10.0.22621.0 +call "%VSINSTALL%\Common7\Tools\VsDevCmd.bat" -arch=amd64 -host_arch=amd64 if ERRORLEVEL 1 exit /B %ERRORLEVEL% rem Save working directory so that we can restore it back after building everything. This will make developers happy and then From dc12f974c2d75bb3965b60f586b417a33dc8463e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Desbiens?= Date: Wed, 26 Aug 2026 16:15:42 -0400 Subject: [PATCH 4/6] Pointed the demo test back at the guix project that exists The demo compile test could not build the GUIX library at all: Exception: guix.sln not found. path=../../../ports/win32/build/vs_2022/guix.vcxproj 522aafcc ("Updated scripts for VS Community 2022", February 2025) moved three paths in test_main.py from vs_2019 to vs_2022. Two of them were right: guix_studio/build/vs_2019 really had been renamed to vs_2022. The third was collateral damage from the same search and replace -- ports/win32/build/vs_2019 was never renamed, and still holds the only guix.vcxproj and guix.sln in the repository. So --build_guix has raised this exception for eighteen months, before compiling a single library configuration. Nothing said so, because the workflow that calls it never reached a runner. Restored the vs_2019 path. Verified by building the library locally: guix.vcxproj is Win32-only and still on PlatformToolset v142, and it produces Debug/gx.lib. Assisted-by: Claude Code (Opus 5) Co-Authored-By: Claude Opus 5 (1M context) --- test/guix_studio_test/test_demo/test_main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/guix_studio_test/test_demo/test_main.py b/test/guix_studio_test/test_demo/test_main.py index 76f5af255..7b2f8ebf7 100644 --- a/test/guix_studio_test/test_demo/test_main.py +++ b/test/guix_studio_test/test_demo/test_main.py @@ -641,7 +641,7 @@ def __main__(): os.chdir(current_path) studio_sln_path = "../../../guix_studio/build/vs_2022/studiox.sln" studio_exe_path = "../../../guix_studio/build/vs_2022/Release/guix_studio.exe" - guix_project_path = "../../../ports/win32/build/vs_2022/guix.vcxproj" + guix_project_path = "../../../ports/win32/build/vs_2019/guix.vcxproj" gxp_projects = [] From eb7cb97e6d0c689809054da96edfce12ddce1849 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Desbiens?= Date: Wed, 26 Aug 2026 16:47:52 -0400 Subject: [PATCH 5/6] Pointed the view test at the Studio build directory that exists The Studio view test could not start the Studio at all: MSBUILD : error MSB1009: Project file does not exist. Switch: ../../../guix_studio/build/vs_2019/studiox.sln Exception: Unable to locate Studio executable. 522aafcc ("Updated scripts for VS Community 2022", February 2025) renamed guix_studio/build/vs_2019 to vs_2022 and updated test_demo/test_main.py for it, but never touched the test_view directory. Three references there still named the old directory: - test_view/test_main.py project_sln_path - test_view/test_utils.py studio_exe_path - test_view/test_string_import_export.py studio_release So this suite has been unable to locate the Studio for eighteen months. Like the guix.vcxproj path in the preceding commit, nothing reported it, because the workflow that runs it never reached a runner. The remaining build/vs_2019 references in the tree belong to ports/win32/build/vs_2019, which is a real directory and is left alone. This commit makes the suite able to find and launch the Studio. Whether it then passes on a hosted runner is a separate question -- it drives the Studio through win32 window handles, and no run has got far enough to say. Its trigger branches are deliberately not changed here for that reason. Assisted-by: Claude Code (Opus 5) Co-Authored-By: Claude Opus 5 (1M context) --- test/guix_studio_test/test_view/test_main.py | 2 +- test/guix_studio_test/test_view/test_string_import_export.py | 2 +- test/guix_studio_test/test_view/test_utils.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/test/guix_studio_test/test_view/test_main.py b/test/guix_studio_test/test_view/test_main.py index 1146e3558..6cf431b4d 100644 --- a/test/guix_studio_test/test_view/test_main.py +++ b/test/guix_studio_test/test_view/test_main.py @@ -82,7 +82,7 @@ def __main__(): logging.basicConfig(stream=test_utils.test_log_stream, level=logging.DEBUG, format=Format) msbuild_exe_path = "C:/Windows/Microsoft.NET/Framework64/v4.0.30319/MSBuild.exe" - project_sln_path = "../../../guix_studio/build/vs_2019/studiox.sln" + project_sln_path = "../../../guix_studio/build/vs_2022/studiox.sln" parser = argparse.ArgumentParser(description = "Test Studio UI") parser.add_argument('-b', action='store_true', dest='build_studio', help='Build Studio') diff --git a/test/guix_studio_test/test_view/test_string_import_export.py b/test/guix_studio_test/test_view/test_string_import_export.py index 231b8d039..db513bbcf 100644 --- a/test/guix_studio_test/test_view/test_string_import_export.py +++ b/test/guix_studio_test/test_view/test_string_import_export.py @@ -98,7 +98,7 @@ def csv_string_import_export(): print("import string from command line") test_utils.toolbar_save() test_utils.close_project(1) - studio_release = test_utils.DEFAULT_OUTPUT_FILE_PATH + "../../../../guix_studio/build/vs_2019/Release/guix_studio.exe" + studio_release = test_utils.DEFAULT_OUTPUT_FILE_PATH + "../../../../guix_studio/build/vs_2022/Release/guix_studio.exe" project_pathname = test_utils.DEFAULT_OUTPUT_FILE_PATH + "/test_string_import_export.gxp" studio_release = os.path.abspath(studio_release) project_pathname = os.path.abspath(project_pathname) diff --git a/test/guix_studio_test/test_view/test_utils.py b/test/guix_studio_test/test_view/test_utils.py index dc7b5d18f..17e43fb05 100644 --- a/test/guix_studio_test/test_view/test_utils.py +++ b/test/guix_studio_test/test_view/test_utils.py @@ -28,7 +28,7 @@ user32 = ctypes.windll.user32 -studio_exe_path = "../../../guix_studio/build/vs_2019/Release/guix_studio.exe" +studio_exe_path = "../../../guix_studio/build/vs_2022/Release/guix_studio.exe" top_windows = [] WM_CLOSE = 0x0010 reset_map_format = False From 19551ffc7907bbe49461f902b1f07ef2979f7b17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Desbiens?= Date: Wed, 26 Aug 2026 16:48:48 -0400 Subject: [PATCH 6/6] Ran the Studio demo suites on dev, where the pull requests actually are The demo and demo compile workflows trigger on master only, for both push and pull_request. dev is the integration branch, so these suites have gated no pull request that anybody opened -- the same defect eclipse-threadx/threadx fixed in its own regression suites in August 2026. Switched on only after both suites were verified green on a runner, on this branch, rather than on the assumption that they would be: GUIX Studio Demo Test 227 of 227 generation tests 147 s GUIX Studio Demo Compile Test 212 of 212 compile tests 146 s The other three workflows are deliberately left on their current triggers, and each for its own reason: - regression_test.yml does reach a runner, and is red. Its last real run, 2026-06-30, was 5 failures out of 732: accordion menu, ml_text_view_32bpp, animation_complete, animation_complete_push_stack and one more. Adding dev here would make every pull request red on a suite that has been broken since June. It needs fixing first, and that is not this change. - studio_view_test.yml can now find the Studio again, but no run has got far enough to say whether GUI automation through win32 window handles survives a hosted runner. Enabling gating on an unknown is what this commit is written to avoid. - studio_msix_package.yml is workflow_dispatch only by design. It packages a release rather than testing a change, so there is nothing to gate. Assisted-by: Claude Code (Opus 5) Co-Authored-By: Claude Opus 5 (1M context) --- .github/workflows/studio_demo_test.yml | 12 +++++++----- .github/workflows/studio_demo_test_compile.yml | 12 +++++++----- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/.github/workflows/studio_demo_test.yml b/.github/workflows/studio_demo_test.yml index fcc9baee2..ac48a7d75 100644 --- a/.github/workflows/studio_demo_test.yml +++ b/.github/workflows/studio_demo_test.yml @@ -12,14 +12,16 @@ name: GUIX Studio Demo Test -# Controls when the action will run. Triggers the workflow on push or pull request -# events but only for the master branch +# Controls when the action will run. dev is included deliberately: it is the +# integration branch, so a master-only trigger gated no pull request that +# anybody opened. Verified green on a runner before being switched on -- +# 227 of 227 generation tests and 212 of 212 compile tests. on: - workflow_dispatch: + workflow_dispatch: push: - branches: [ master ] + branches: [ master, dev ] pull_request: - branches: [ master ] + branches: [ master, dev ] # A workflow run is made up of one or more jobs that can run sequentially or in parallel jobs: diff --git a/.github/workflows/studio_demo_test_compile.yml b/.github/workflows/studio_demo_test_compile.yml index 59c2ea995..a5c9142c9 100644 --- a/.github/workflows/studio_demo_test_compile.yml +++ b/.github/workflows/studio_demo_test_compile.yml @@ -12,14 +12,16 @@ name: GUIX Studio Demo Compile Test -# Controls when the action will run. Triggers the workflow on push or pull request -# events but only for the master branch +# Controls when the action will run. dev is included deliberately: it is the +# integration branch, so a master-only trigger gated no pull request that +# anybody opened. Verified green on a runner before being switched on -- +# 227 of 227 generation tests and 212 of 212 compile tests. on: - workflow_dispatch: + workflow_dispatch: push: - branches: [ master ] + branches: [ master, dev ] pull_request: - branches: [ master ] + branches: [ master, dev ] # A workflow run is made up of one or more jobs that can run sequentially or in parallel jobs: