-
Notifications
You must be signed in to change notification settings - Fork 0
212 lines (187 loc) · 8.83 KB
/
Copy pathengine-repin.yml
File metadata and controls
212 lines (187 loc) · 8.83 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
name: Engine re-pin
# Daily check for a new release of any vendored engine (codeindex, webindex).
# If every pin is already on its latest v* tag, this is a green no-op.
# Otherwise it re-pins the stale ones, rebuilds the bundle, and runs the same
# gates as ci.yml:
# - all green -> commit + push straight to main, then explicitly trigger
# release.yml and ci.yml (a GITHUB_TOKEN push does NOT fire
# other workflows, so `gh workflow run` is required).
# - any gate red -> the run simply fails (no push, no adjudication PR);
# the next daily cron retries. A red run is the signal
# to investigate locally.
#
# The engine list is NOT duplicated here. `sync-engine.mjs --list` prints one
# `<name> <repo> <pinned-tag>` line per engine, so adding an engine is a
# one-line edit in that script and this workflow follows automatically — the
# automation cannot drift from the list it is supposed to be watching.
#
# All stale engines are re-pinned in ONE commit and gated together: they are
# inlined into the same bundle, so testing them separately would prove less and
# cost two CI runs.
#
# No secrets beyond the built-in GITHUB_TOKEN.
on:
schedule:
- cron: "17 6 * * *" # daily; minute offset staggers load across repos
workflow_dispatch: {}
permissions:
contents: write
actions: write
issues: write
concurrency: engine-repin
jobs:
repin:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0
persist-credentials: true
- uses: pnpm/action-setup@v6
- uses: actions/setup-node@v6
with:
node-version: 24
cache: pnpm
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Re-pin every engine that has a newer release
id: detect
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
set -euo pipefail
SUMMARY=""
while read -r NAME REPO PINNED; do
# NOT releases/latest: a repo may also publish non-engine asset
# releases (codeindex publishes embed-model-v1), which are not tags
# this can pin to.
LATEST=$(gh api "repos/${REPO}/releases" --jq '[.[] | select(.tag_name | test("^v[0-9]")) | .tag_name] | first')
if [ -z "$LATEST" ] || [ "$LATEST" = "null" ]; then
echo "::error::could not determine the latest ${NAME} release tag"
exit 1
fi
if [ "$PINNED" = "$LATEST" ]; then
echo "${NAME}: up to date (${PINNED})"
continue
fi
echo "${NAME}: ${PINNED} -> ${LATEST}"
node scripts/sync-engine.mjs --engine "$NAME" --ref "$LATEST"
SUMMARY="${SUMMARY}${NAME} ${PINNED} -> ${LATEST}"$'\n'
done < <(node scripts/sync-engine.mjs --list)
if [ -z "$SUMMARY" ]; then
echo "repin=false" >> "$GITHUB_OUTPUT"
else
echo "repin=true" >> "$GITHUB_OUTPUT"
{
echo "summary<<EOF"
printf '%s' "$SUMMARY"
echo "EOF"
} >> "$GITHUB_OUTPUT"
fi
- name: Verify the vendored engines match their new pins
if: steps.detect.outputs.repin == 'true'
run: node scripts/sync-engine.mjs --check
- name: Typecheck
if: steps.detect.outputs.repin == 'true'
run: pnpm run typecheck
- name: Lint
if: steps.detect.outputs.repin == 'true'
run: pnpm run lint
- name: Rebuild the bundle
if: steps.detect.outputs.repin == 'true'
run: pnpm run build
# check:build's own `git diff --exit-code` compares the working tree to
# the index. Stage the rebuild here so that internal diff is clean —
# same as the local flow (rebuild, `git add`, then verify).
- name: Stage the rebuilt bundle + vendor pins
if: steps.detect.outputs.repin == 'true'
run: git add -A src/vendor scripts skills
- name: Build is reproducible
if: steps.detect.outputs.repin == 'true'
run: pnpm run check:build
- name: Verify skill bundle shape
if: steps.detect.outputs.repin == 'true'
run: pnpm run verify:bundle
- name: Test (with coverage)
if: steps.detect.outputs.repin == 'true'
run: pnpm run test:coverage
- name: Smoke-run the committed bundle (offline render + check)
if: steps.detect.outputs.repin == 'true'
run: pnpm run demo
- name: Assert the SRD was produced and is structurally complete
if: steps.detect.outputs.repin == 'true'
run: |
test -f /tmp/construct-demo/SRD.json
test -f /tmp/construct-demo/requirements/FUNCTIONAL.md
test -f /tmp/construct-demo/SRD.md
# assets/example-srd is ENGINE OUTPUT: its requirements are rendered from
# evidence the vendored engines gathered, so a bump legitimately moves it.
# Hard-failing on that diff is how a pin rots — ultrasec's sat seven
# releases behind because twelve artifacts moved and every nightly re-pin
# died on them. So regenerate it, and refuse only a LOSS. (`example` also
# re-checks grounding >= 66, so a collapse fails here too.)
- name: Regenerate the engine-output artifacts
if: steps.detect.outputs.repin == 'true'
run: pnpm run example
# …but regenerating a regression gate on autopilot destroys the thing it
# guards, so the regenerated artifacts are compared against the committed
# ones: enrichment passes, anything that got SHORTER fails the run and
# nothing is pushed. Losing something stays a human decision.
- name: Guard — the regenerated artifacts lost nothing
if: steps.detect.outputs.repin == 'true'
run: node scripts/check-artifact-recall.mjs
- name: Commit + push the re-pin to main
if: steps.detect.outputs.repin == 'true'
env:
SUMMARY: ${{ steps.detect.outputs.summary }}
run: |
set -euo pipefail
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git add -A
DIFFSTAT=$(git diff --cached --stat | tail -1)
git commit -m "feat(engine): re-pin vendored engines" -m "automated re-pin, all gates green, goldens byte-identical" -m "${SUMMARY}
${DIFFSTAT}"
git pull --rebase origin main
git push origin HEAD:main
- name: Trigger release + CI on the pushed commit
if: steps.detect.outputs.repin == 'true'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
# A push authenticated with GITHUB_TOKEN does not fire other
# workflows' `on: push` triggers — dispatch them explicitly.
gh workflow run release.yml --ref main
gh workflow run ci.yml --ref main
# A red re-pin means this repo has stopped following the engine. Nothing
# used to carry that signal out of the Actions tab, so ultrasec failed
# three nights running in August before a human noticed. One open issue per
# repo, a comment on each further failure, closed by the first green run.
- name: Report the failure on the tracking issue
if: failure()
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
set -euo pipefail
RUN="${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"
gh label create engine-repin --color B60205 --description "This automated pin needs a human" --force >/dev/null 2>&1 || true
NUM=$(gh issue list --state open --label engine-repin --limit 1 --json number --jq '.[0].number // empty')
# Built with printf rather than a multi-line literal: this file's own
# indentation would otherwise be carried into the body and render the
# whole message as a code block.
BODY=$(printf '%s\n\n%s\n' \
"The daily engine-repin run failed: ${RUN}" \
"Nothing was pushed, so main is not broken — the pin is simply frozen where it was, and this repo stays behind the engine until someone looks.")
if [ -n "$NUM" ]; then
gh issue comment "$NUM" --body "$BODY"
else
gh issue create --title "${{ github.workflow }} is failing" --label engine-repin --body "$BODY"
fi
- name: Close the tracking issue once a run is green
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
set -euo pipefail
NUM=$(gh issue list --state open --label engine-repin --limit 1 --json number --jq '.[0].number // empty')
if [ -z "$NUM" ]; then exit 0; fi
gh issue close "$NUM" --comment "Green again: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"