You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
ci(gh-aw): add CI guard for lock-file drift and compiler-version skew
Add GH_AW_VERSION env var to ci.yml as the single source of truth for the
pinned gh-aw compiler version, and an aw-lock-drift job that installs the
pinned extension, recompiles all agentic workflows, and fails if:
- any .lock.yml or .github/aw file drifts from its .md source
- gh aw compile produces untracked files
- lock files disagree on compiler_version or differ from the pin
Update CLAUDE.md to document the pin and the drift job, with guidance to
install the pinned version instead of upgrading to latest.
Closes#1390
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
- name: Fail on lock-file drift or untracked compiler output
75
+
run: |
76
+
if ! git diff --exit-code -- .github/workflows .github/aw; then
77
+
echo "::error::Lock files are out of date. Install the pinned gh-aw ('gh extension install github/gh-aw --pin $GH_AW_VERSION'), run 'gh aw compile', and commit the result."
78
+
exit 1
79
+
fi
80
+
UNTRACKED=$(git status --porcelain --untracked-files=all -- .github/workflows)
81
+
if [ -n "$UNTRACKED" ]; then
82
+
echo "::error::gh aw compile produced untracked files. Commit them, or delete the orphaned .md source that generated them:"
83
+
echo "$UNTRACKED"
84
+
exit 1
85
+
fi
86
+
87
+
- name: Assert every lock reports the pinned compiler version
echo "::error::No compiler_version found in any .github/workflows/*.lock.yml header."
92
+
exit 1
93
+
fi
94
+
if [ "$(printf '%s\n' "$VERSIONS" | wc -l)" -ne 1 ]; then
95
+
echo "::error::Lock files report multiple gh-aw compiler versions — recompile ALL workflows with the pinned version ($GH_AW_VERSION):"
96
+
printf '%s\n' "$VERSIONS"
97
+
exit 1
98
+
fi
99
+
if [ "$VERSIONS" != "\"compiler_version\":\"$GH_AW_VERSION\"" ]; then
100
+
echo "::error::Locks were compiled with $VERSIONS but GH_AW_VERSION=$GH_AW_VERSION is pinned. Install it ('gh extension install github/gh-aw --pin $GH_AW_VERSION'), run 'gh aw compile', and commit."
Copy file name to clipboardExpand all lines: CLAUDE.md
+21-3Lines changed: 21 additions & 3 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -119,11 +119,19 @@ Never hand-edit a `.lock.yml`: commit both the `.md` source and the regenerated
119
119
120
120
#### Keep every lock file on the same compiler version
121
121
122
-
**All lock files must be compiled with the same `gh aw` version.** The repository is currently on **`v0.86.2`**. The pin is recorded in every lock file's `# gh-aw-metadata:` header as `compiler_version` — there is no separate pin file; the locks themselves are the record. Check yours with `gh aw version` and upgrade with `gh extension upgrade gh-aw` before recompiling.
122
+
**All lock files must be compiled with the same `gh aw` version.** The repository is currently on **`v0.86.2`**. The pin lives in the `GH_AW_VERSION` env var at the top of `.github/workflows/ci.yml` — that is the single source of truth, and every lock file's `# gh-aw-metadata:` header must report the same `compiler_version`.
123
+
124
+
Install the **pinned** version before recompiling:
125
+
126
+
```bash
127
+
gh extension install github/gh-aw --pin v0.86.2 # use the GH_AW_VERSION value from ci.yml
128
+
```
129
+
130
+
Do **NOT** run `gh extension upgrade gh-aw` — upgrading floats to the latest release, and if latest differs from the pin your recompiled locks will fail the `aw-lock-drift` CI job spuriously. Check what you have with `gh aw version`.
123
131
124
132
Recompiling a single workflow with a newer extension than the others introduces *compiler version skew*. Each lock file embeds a pinned [`gh-aw-firewall`](https://github.com/githubnext/gh-aw-firewall) (AWF) release, so a skewed lock ends up on a different AWF pin than its siblings. Upstream deletes old AWF releases, and when that happens the `Install AWF binary` step dies with `curl: (22) ... 404` and the workflow fails 100% of the time — which is exactly how `reverse-binary-analysis` (pinned to the deleted `v0.25.28`) silently failed every week for over two months ([#1388](https://github.com/TheLarkInn/aipm/issues/1388)).
125
133
126
-
When upgrading the extension, run a bare `gh aw compile` to recompile **all** workflows at once, and confirm the pins agree before committing:
134
+
When bumping the pin, update `GH_AW_VERSION` in `ci.yml`, install that version, run a bare `gh aw compile` to recompile **all** workflows at once, and confirm the AWF pins agree before committing:
@@ -135,6 +143,16 @@ That must print exactly one version, and it must resolve upstream:
135
143
gh api repos/githubnext/gh-aw-firewall/releases/tags/<version> --jq .tag_name
136
144
```
137
145
146
+
#### The `aw-lock-drift` CI job enforces all of this
147
+
148
+
The `aw-lock-drift` job in `ci.yml` fails the build when the committed locks drift from the `.md` sources or the pin. It installs gh-aw at exactly `GH_AW_VERSION` (`gh extension install github/gh-aw --pin`), runs `gh aw compile`, and fails if:
149
+
150
+
-`git diff --exit-code -- .github/workflows .github/aw` shows any change — an `.md` was edited (or gh-aw bumped) without committing the regenerated `.lock.yml` ([#1390](https://github.com/TheLarkInn/aipm/issues/1390))
151
+
-`git status --porcelain --untracked-files=all -- .github/workflows` is non-empty — compile emitted an untracked file, the orphaned-source class of bug
152
+
- the `# gh-aw-metadata:` headers disagree on `compiler_version`, or report anything other than `GH_AW_VERSION` — compiler-version skew
153
+
154
+
If it fails on your PR, install the pinned version and recompile as shown above, then commit every regenerated file.
155
+
138
156
#### Lock files are generated — `.gitattributes` is deliberately minimal
139
157
140
158
`.gitattributes` carries exactly one rule for the compiled locks:
@@ -143,7 +161,7 @@ gh api repos/githubnext/gh-aw-firewall/releases/tags/<version> --jq .tag_name
`linguist-generated=true` keeps the generated locks out of PR diffs and repo language stats. The rule **deliberately does not** set `merge=ours` ([#1392](https://github.com/TheLarkInn/aipm/issues/1392)): `merge=ours` only works when every contributor configures the `ours` merge driver locally (`git config merge.ours.driver true`), so it was inert for most clones, and when it *did* fire it silently resolved lock conflicts to the local side instead of regenerating from the `.md` source — precisely the drift this section exists to prevent. A conflict in a lock file must be resolved by recompiling (`gh aw compile`), never by keeping one side, so a loud conflict is the desired behaviour. The follow-up CI guard in [#1390](https://github.com/TheLarkInn/aipm/issues/1390) makes out-of-date locks fail the build outright.
164
+
`linguist-generated=true` keeps the generated locks out of PR diffs and repo language stats. The rule **deliberately does not** set `merge=ours` ([#1392](https://github.com/TheLarkInn/aipm/issues/1392)): `merge=ours` only works when every contributor configures the `ours` merge driver locally (`git config merge.ours.driver true`), so it was inert for most clones, and when it *did* fire it silently resolved lock conflicts to the local side instead of regenerating from the `.md` source — precisely the drift this section exists to prevent. A conflict in a lock file must be resolved by recompiling (`gh aw compile`), never by keeping one side, so a loud conflict is the desired behaviour. The `aw-lock-drift` CI guard ([#1390](https://github.com/TheLarkInn/aipm/issues/1390)) makes out-of-date locks fail the build outright.
147
165
148
166
#### `agentics-maintenance.yml` is generated and adopted
0 commit comments