Repository navigation
Commit 671df26
Move the three untested inline workflow step bodies into scripts/ci with self-tests (#26386)
<!-- claude-projects-attribution: {"github_login":"os-steve"} -->
_Requested by **Steve** · [project
thread](https://claude.ai/code/project/chan_01FdL1XeUyvVNxLreh3F4Qi9?thread=cmsg_01FdL1XeUyvVNxLreh3F4Qi95YovdFSHTxz132KjPG4TAa)_
Part of #26086
Clause-②: no
Metadata-protocol: none
## 维护者速读
- 改了什么:三个只在「没有 PR 能触发的事件」上跑的工作流步骤(定时全量红卡、nightly 红卡、看板备份上传 R2),把内联主体搬进
`scripts/ci/`,每个都配了离线自测,并接进 `lint-ci-engine` 道。
- 为什么改:这三段主体原来没有任何测试能碰到,第一次执行就是线上真跑。卡上其余 17 个超 80
行的主体,大多已经有门禁在读它的原样字节;release.yml 的 3 步有信任边界,不能搬。逐个原因见下文 Acceptance
notes。
- 风险与回滚:行为不变。github-script 步骤保留原来的 token、`retries:` 和权限,只是改成 import
模块后薄调用;bash 主体逐字节不变。回滚就是 revert 这个 PR。
-
先看:`scripts/ci/scheduled-full-run-card.mjs`(调用和回调接线)、`scripts/ci/nightly-tiers-card.mjs`、`.github/workflows/lint.yml`
新增的那一步。
- 两分钟验证:`node scripts/ci/scheduled-full-run-card.mjs --self-test && node
scripts/ci/nightly-tiers-card.mjs --self-test && bash
scripts/ci/board-snapshot-r2-upload.selftest.sh`,三行 ✓,共 7 + 7 + 5 个用例。
- 需要你做的:这是 Tier H(改 `.github/workflows/**`),需要
GOVERNED_APPROVERS(os-zhuang 或 hotlong)批准;PR 1
的范围(只搬没有测试台的部分,还是照卡全搬)在项目线程里等 Steve 裁决。
## What changes
Three inline step bodies that no test reached move into `scripts/ci/`,
each with an offline self-test:
| Workflow step | Lines moved | New home | Self-test |
|---|---|---|---|
| `scheduled-full-run-card.yml` · File or refresh the card
(github-script) | 121 | `scripts/ci/scheduled-full-run-card.mjs` ·
`fileCardStep` | 7 cases |
| `test-nightly-tiers.yml` · File or refresh the card (github-script) |
158 | `scripts/ci/nightly-tiers-card.mjs` · `fileNightlyCard` | 7 cases
|
| `board-snapshot.yml` · Upload the archive to R2 (run) | 125 |
`scripts/ci/board-snapshot-r2-upload.sh` |
`scripts/ci/board-snapshot-r2-upload.selftest.sh`, 5 cases / 27 checks |
- **github-script bodies keep their step.** The step now does `await
import(GITHUB_WORKSPACE + '/scripts/ci/X.mjs')` and calls the exported
function with the same `github` / `context` / `core`. That keeps the
token, the `retries:` / `retry-exempt-status-codes:` policy and the
job's `permissions:` exactly as they were. It follows
`scheduled-full-run-card.yml`'s existing import of
`scripts/ci/scheduled-full-run.mjs`. This is a deliberate deviation from
the card's literal "the YAML step becomes `node scripts/ci/X.mjs`": a
bare `node` step would need its own octokit, token plumbing and retry
policy, which is a behaviour change. Both jobs already check out the
repository.
- **The bash body moves byte for byte.**
`scripts/ci/board-snapshot-r2-upload.sh` is the inline block plus a
header and the `set -e` that GitHub's default `bash -e {0}` shell
supplied. `cmp` against the YAML-parsed block is identical. The step
keeps its `env:` and runs `bash scripts/ci/board-snapshot-r2-upload.sh`.
- **Spelling changes inside the moved JS, and only these:**
`require('fs')` / `require('path')` became static imports. `process.env`
became an `env` parameter that defaults to `process.env`. The two `new
Date()` reads that stamp a body became an injectable `now` that defaults
to `new Date()`. The import of `scheduled-full-run.mjs` became static.
- **Wiring:** one new gate step in `lint-ci-engine`, `Moved workflow
step bodies self-test` (with an `id:` and `continue-on-error: true`, so
the lane verdict reads it), runs all three self-tests through the repo's
`run_self_test` collector, so one red does not hide the others.
- **Adoption lists:** `board-snapshot.yml`'s header and
`scripts/pm/board-snapshot.mjs`'s docblock both said "copy FOUR files".
The R2 step now needs a fifth, so both lists name it. That is the one
prose edit, and it is the card's own carve-out: a literal the touched
step makes false.
- **Found while moving:** the root `.gitignore` ignores `test-*.mjs`, so
the nightly module could not be named `test-nightly-tiers-card.mjs`. Its
first push silently left it out, and it is now `nightly-tiers-card.mjs`.
## Tests
Behaviour preservation was checked before each move, against the inline
bodies at `6390fe52` (main when this branch was cut):
- **github-script bodies:** a one-off harness ran the inline body
extracted from the YAML (compiled the way `actions/github-script`
compiles it) and then the module, under identical doubles, files and a
frozen clock. It recorded every API call with its full parameters,
bodies included, and every `core` call. The traces are identical:
`scheduled-full-run-card` 7/7 scenarios, `nightly-tiers-card` 7/7. The
committed self-tests pin the values taken from those traces. For the
scheduled card the body is pinned as exact `renderBody(...)` arguments,
so a wording change in `scheduled-full-run.mjs` does not red this file.
For the nightly card it is pinned as the SHA-256 of the inline body's
bytes.
- **bash body:** the committed self-test passes against the inline block
(extracted from the YAML at `6390fe52`) and against the moved script.
Negative control: with `--delete` dropped from the sync line, two checks
go red.
- Each self-test carries a battery roster with per-case floors, a pinned
roster size and a verdict handshake (AGENTS.md, "Writing a
`--self-test`").
Derived gate families: `node scripts/pm/dispatch-gates.mjs --commands
--repo objectstack-ai/objectstack` gives 60 commands. Results are below.
CI runs the rest.
**60 derived, 60 run, 0 red.** `node scripts/pm/dispatch-gates.mjs --ran
ran.list` gives `60 derived famil(ies) accounted for — 60 run, 0
NOT-MEASURED`. The first round had 4 reds, all caused by this diff and
fixed in `b422bbdf`:
- `pnpm check:bash32-floor`: the R2 self-test's roster used `declare
-A`. It now uses parallel indexed arrays.
- `node scripts/check-step-collectors.mjs` (and its `--self-test`): the
new lint step ran its three self-tests as a bare sequence. It now uses
the `run_self_test` collector.
- `pnpm check:declared-population-live`: the nightly self-test spelled
its `$RUNNER_TEMP` fixture paths as literals, so they read as a declared
population. It now builds them and carries a `no-path-population`
marker.
Not in the derived list, run by hand: `bash
scripts/ci/board-snapshot-r2-upload.selftest.sh` passes (5 cases, 27
checks), and the new lint step's `run:` block, extracted from the YAML
and run under `bash -e`, prints three `PASS` lines.
<details><summary>Second-round results (exit code, command,
seconds)</summary>
```
0 node scripts/check-aggregator-roster.mjs 0s
0 node scripts/check-aggregator-roster.mjs --self-test 2s
0 node scripts/check-ci-filter-parity.mjs 0s
0 node scripts/check-closing-keyword-parity.mjs 2s
0 node scripts/check-closing-keyword-parity.mjs --self-test 5s
0 node scripts/check-comment-mask-corpus.mjs 181s
0 node scripts/check-declaration-mirrors.mjs 1s
0 node scripts/check-declaration-mirrors.mjs --self-test 0s
0 node scripts/check-merged-branch-reaper-outcome.mjs 0s
0 node scripts/check-merged-branch-reaper-outcome.mjs --self-test 0s
0 node scripts/check-scripts-symbol-anchors.mjs 3s
0 node scripts/check-scripts-symbol-anchors.mjs --self-test 4s
0 node scripts/check-self-test-wired.mjs 2s
0 node scripts/check-self-test-wired.mjs --self-test 5s
0 node scripts/check-self-test-workflow-commands.mjs 116s
0 node scripts/check-self-test-workflow-commands.mjs --self-test 3s
0 node scripts/check-step-collectors.mjs 1s
0 node scripts/check-step-collectors.mjs --self-test 5s
0 node scripts/check-whole-set-label-write.mjs 2s
0 node scripts/check-whole-set-label-write.mjs --self-test 1s
0 node scripts/ci/nightly-tiers-card.mjs --self-test 0s
0 node scripts/ci/scheduled-full-run-card.mjs --self-test 0s
0 node scripts/ci/scheduled-full-run.mjs --self-test 0s
0 node scripts/docs-audit/check-drift-comment.mjs 1s
0 node scripts/nightly-tiers.mjs --self-test 0s
0 node scripts/pm/bare-root-worklist.mjs --self-test 30s
0 node scripts/pm/board-snapshot.mjs --self-test 1s
0 node scripts/pm/ci-failure.mjs --self-test 0s
0 pnpm check:agent-test-spelling 3s
0 pnpm check:bash32-floor 2s
0 pnpm check:cli-command-ids 17s
0 pnpm check:cross-package-test-inputs 33s
0 pnpm check:declared-population-live 36s
0 pnpm check:driver-memory-census 5s
0 pnpm check:entry-guard 38s
0 pnpm check:gitlink-declared 1s
0 pnpm check:node-version 1s
0 pnpm check:nul-bytes 4s
0 pnpm check:parse-guard 3s
0 pnpm check:pm-board-snapshot 2s
0 pnpm check:pm-dispatch-gates 396s
0 pnpm check:pm-expected-skips 6s
0 pnpm check:pm-governed-merges 9s
0 pnpm check:pm-post-stamped 1s
0 pnpm check:pm-record-recognisers 4s
0 pnpm check:pnpm-acquisition 1s
0 pnpm check:pnpm-filter-targets 3s
0 pnpm check:pnpm-flag-spellings 6s
0 pnpm check:ratchet-remedy-authority 4s
0 pnpm check:refd-timer-probe 23s
0 pnpm check:required-contexts 4s
0 pnpm check:select-gate-families 4s
0 pnpm check:shard-attestation 3s
0 pnpm check:stall-guard-budget 1s
0 pnpm check:stall-guard-headroom 5s
0 pnpm check:type-check-coverage 5s
0 pnpm check:type-check-debt 6s
0 pnpm check:watch-hint-literal 7s
0 pnpm check:workflow-status-functions 1s
0 pnpm check:workflow-step-name-quoting 1s
```
</details>
## Acceptance notes
**The card's premise holds for a minority of the volume.** On
`6390fe52`: 20 inline bodies over 80 lines, 4,414 lines. Most of those
lines are already exercised byte-for-byte by a gate that reads the YAML,
so moving them buys no test reach and means rewriting the harness:
| Body (lines) | What already reads its bytes | Status |
|---|---|---|
| merge-queue-triage · Post the triage comment (901) |
`check-merge-queue-triage-outcome.mjs` compiles it as github-script
does, 28 mutations; its P0 also pins that the job holds no `contents:`
grant, which a checkout for an import would need | stays |
| docs-drift-check · Comment on PR (597) |
`docs-audit/check-drift-comment.mjs` runs it against fixture diffs |
stays |
| cross-repo-issue-closer (416) | `check-cross-repo-closer-outcome.mjs`
(executes), `check-closing-keyword-parity.mjs` (mutates its regex) |
stays |
| release.yml · Audit the release (277) | `release-verify-npm.mjs`
batteries 12/13 run the step text | stays |
| merged-branch-reaper (174) | `check-merged-branch-reaper-outcome.mjs`
(executes) | stays |
| shard-timings-refresh · Choose (82), Regenerate (136) |
`ci/select-shard-timings-run.mjs` runs both | stays |
| shard-timings-refresh · Compose (206) | text pin in
`ci/select-shard-timings-run.mjs` | stays |
| shard-timings-refresh · Push (102) | executed for real on every
`pull_request` run of the lane (the `DRY_RUN` leg) | stays |
| pr-automation · Require a changeset (167) | text pins in
`check-empty-changeset.mjs` | stays |
| platform-checklist-watchdog (145) |
`check-platform-checklist-watchdog.mjs` scans the script for board
writes; moving it would blind that negative pin | stays |
| duplicate-fix-guard (108) | `check-closing-keyword-parity.mjs` mutates
its regex | stays |
| release.yml · Guard the approved release (99) | trust boundary: the
`publish` job checks out the VERSION COMMIT, so a moved guard would be
read from the tree it is guarding | stays |
| release.yml · Render (84), Validate (167) the post-version tree |
trust boundary: both run after `changeset version` has written the
working tree, so a moved validator would be read from the tree it
validates | stays |
| ci.yml · Run this shard's tests (185) | the step #26084 is changing;
moves after it lands | deferred |
| cut-rc.yml · Build the single version commit (164) | the file is
deleted by #26196 | out |
| the three above | nothing | **moved here** |
After this PR: 17 bodies over 80 lines, 4,010 lines (the census re-run
on the branch). Whether the harnessed bodies should move anyway, which
means rewriting about ten harnesses and granting `contents: read` to
jobs that hold none today, is the open scope question for this card's PR
1. It is in front of the maintainer in the project thread. This PR is
the part both answers need.
## Verification
```sh
node scripts/ci/scheduled-full-run-card.mjs --self-test
node scripts/ci/nightly-tiers-card.mjs --self-test
bash scripts/ci/board-snapshot-r2-upload.selftest.sh
```
Tier H (`.github/workflows/**`): draft until a GOVERNED_APPROVERS
approval (os-zhuang, hotlong).
---
_Generated by [Claude
Code](https://claude.ai/code/session_01ADHkmQq9EYQdTQwmRutQTS)_
🤖 Generated with [Claude Code](https://claude.com/claude-code)
https://claude.ai/code/session_01ADHkmQq9EYQdTQwmRutQTS
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent b33dd25 commit 671df26
9 files changed
Lines changed: 1348 additions & 410 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
118 | 118 | | |
119 | 119 | | |
120 | 120 | | |
121 | | - | |
| 121 | + | |
122 | 122 | | |
123 | | - | |
124 | | - | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
125 | 126 | | |
126 | 127 | | |
127 | 128 | | |
| |||
392 | 393 | | |
393 | 394 | | |
394 | 395 | | |
395 | | - | |
396 | | - | |
397 | | - | |
398 | | - | |
399 | | - | |
400 | | - | |
401 | | - | |
402 | | - | |
403 | | - | |
404 | | - | |
405 | | - | |
406 | | - | |
407 | | - | |
408 | | - | |
409 | | - | |
410 | | - | |
411 | | - | |
412 | | - | |
413 | | - | |
414 | | - | |
415 | | - | |
416 | | - | |
417 | | - | |
418 | | - | |
419 | | - | |
420 | | - | |
421 | | - | |
422 | | - | |
423 | | - | |
424 | | - | |
425 | | - | |
426 | | - | |
427 | | - | |
428 | | - | |
429 | | - | |
430 | | - | |
431 | | - | |
432 | | - | |
433 | | - | |
434 | | - | |
435 | | - | |
436 | | - | |
437 | | - | |
438 | | - | |
439 | | - | |
440 | | - | |
441 | | - | |
442 | | - | |
443 | | - | |
444 | | - | |
445 | | - | |
446 | | - | |
447 | | - | |
448 | | - | |
449 | | - | |
450 | | - | |
451 | | - | |
452 | | - | |
453 | | - | |
454 | | - | |
455 | | - | |
456 | | - | |
457 | | - | |
458 | | - | |
459 | | - | |
460 | | - | |
461 | | - | |
462 | | - | |
463 | | - | |
464 | | - | |
465 | | - | |
466 | | - | |
467 | | - | |
468 | | - | |
469 | | - | |
470 | | - | |
471 | | - | |
472 | | - | |
473 | | - | |
474 | | - | |
475 | | - | |
476 | | - | |
477 | | - | |
478 | | - | |
479 | | - | |
480 | | - | |
481 | | - | |
482 | | - | |
483 | | - | |
484 | | - | |
485 | | - | |
486 | | - | |
487 | | - | |
488 | | - | |
489 | | - | |
490 | | - | |
491 | | - | |
492 | | - | |
493 | | - | |
494 | | - | |
495 | | - | |
496 | | - | |
497 | | - | |
498 | | - | |
499 | | - | |
500 | | - | |
501 | | - | |
502 | | - | |
503 | | - | |
504 | | - | |
505 | | - | |
506 | | - | |
507 | | - | |
508 | | - | |
509 | | - | |
510 | | - | |
511 | | - | |
512 | | - | |
513 | | - | |
514 | | - | |
515 | | - | |
516 | | - | |
517 | | - | |
518 | | - | |
519 | | - | |
520 | | - | |
| 396 | + | |
| 397 | + | |
| 398 | + | |
521 | 399 | | |
522 | 400 | | |
523 | 401 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
3473 | 3473 | | |
3474 | 3474 | | |
3475 | 3475 | | |
| 3476 | + | |
| 3477 | + | |
| 3478 | + | |
| 3479 | + | |
| 3480 | + | |
| 3481 | + | |
| 3482 | + | |
| 3483 | + | |
| 3484 | + | |
| 3485 | + | |
| 3486 | + | |
| 3487 | + | |
| 3488 | + | |
| 3489 | + | |
| 3490 | + | |
| 3491 | + | |
| 3492 | + | |
| 3493 | + | |
| 3494 | + | |
| 3495 | + | |
| 3496 | + | |
| 3497 | + | |
| 3498 | + | |
| 3499 | + | |
| 3500 | + | |
| 3501 | + | |
| 3502 | + | |
| 3503 | + | |
| 3504 | + | |
| 3505 | + | |
| 3506 | + | |
| 3507 | + | |
3476 | 3508 | | |
3477 | 3509 | | |
3478 | 3510 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
161 | 161 | | |
162 | 162 | | |
163 | 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 | | - | |
213 | | - | |
214 | | - | |
215 | | - | |
216 | | - | |
217 | | - | |
218 | | - | |
219 | | - | |
220 | | - | |
221 | | - | |
222 | | - | |
223 | | - | |
224 | | - | |
225 | | - | |
226 | | - | |
227 | | - | |
228 | | - | |
229 | | - | |
230 | | - | |
231 | | - | |
232 | | - | |
233 | | - | |
234 | | - | |
235 | | - | |
236 | | - | |
237 | | - | |
238 | | - | |
239 | | - | |
240 | | - | |
241 | | - | |
242 | | - | |
243 | | - | |
244 | | - | |
245 | | - | |
246 | | - | |
247 | | - | |
248 | | - | |
249 | | - | |
250 | | - | |
251 | | - | |
252 | | - | |
253 | | - | |
254 | | - | |
255 | | - | |
256 | | - | |
257 | | - | |
258 | | - | |
259 | | - | |
260 | | - | |
261 | | - | |
262 | | - | |
263 | | - | |
264 | | - | |
265 | | - | |
266 | | - | |
267 | | - | |
268 | | - | |
269 | | - | |
270 | | - | |
271 | | - | |
272 | | - | |
273 | | - | |
274 | | - | |
275 | | - | |
276 | | - | |
277 | | - | |
278 | | - | |
279 | | - | |
280 | | - | |
281 | | - | |
282 | | - | |
283 | | - | |
284 | | - | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
285 | 168 | | |
286 | 169 | | |
287 | 170 | | |
| |||
0 commit comments