Skip to content

Commit 4365d12

Browse files
authored
redline pin bump: redline-post.yml is a caller (#153)
* redline pin bump: redline-post.yml is a caller redline-post.yml pins redline-post-verdict.yml and passes the same sha as redline-ref, the shape of the other three callers. pin.mjs lists it in CALLERS, and the bump wave reads it, checks its grants against redline-post-verdict.yml and moves both lines with the others. A change to redline-post-verdict.yml now moves the pins. * redline: name the ops tick, not forge
1 parent 49d2f38 commit 4365d12

14 files changed

Lines changed: 88 additions & 67 deletions

‎.github/workflows/public-text.yml‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
# model or an AI tool (scripts/redline/public-text.mjs). The review leaves dashes to this check,
44
# and a credit, which the review also blocks, is caught here in seconds, before a review round;
55
# every one shows in a single run.
6-
# It is its own workflow, apart from the review: the forge posts a Redline verdict only when the
6+
# It is its own workflow, apart from the review: a Redline verdict is posted only when the
77
# review run's conclusion agrees with it, so a failing job inside that run would hold back an
88
# approval.
99
# It reads the pull request through the API and checks out none of its code, so a fork PR is

‎.github/workflows/redline-fix-run.yml‎

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
# Redline fix: the first-party answer to a Redline REQUEST_CHANGES, as a CI job. Each repository
2-
# calls this from its own redline-fix.yml (workflow_dispatch; forge dispatches it with the PR, the
2+
# calls this from its own redline-fix.yml (workflow_dispatch; the ops tick dispatches it with the PR, the
33
# head Redline reviewed and the review). The job checks out that head on the repository's own
44
# non-root exec runner, lets the fix script edit and test inside it, and uploads the result as the
55
# redline-fix artifact: fix.json, notes.md and, when there is a fix, fix.bundle (one commit on top
66
# of the head). The job's status is the outcome: 0 for fixed, or for a description replaced with no
7-
# file changed (forge applies that too); 1 for anything else.
8-
# Nothing here pushes or comments and no token that could is on the runner: forge verifies the
7+
# file changed (the ops tick applies that too); 1 for anything else.
8+
# Nothing here pushes or comments and no token that could is on the runner: the ops tick verifies the
99
# artifact (the run came from the pinned redline-fix.yml, the bundle is one fast-forward commit as
1010
# askalf with no attribution) and pushes it to the PR branch with the token it already holds.
1111
# The model is reached through FIX_ENV_FILE, which only the exec account that runs this job can
@@ -135,7 +135,7 @@ jobs:
135135

136136
# The checkout was asked for the head sha, so this proves only that it landed nowhere else.
137137
# Whether the PR is still at that head is read from the API by fix.mjs before the model is
138-
# called: a PR that moved is refused, and forge dispatches again at its new head.
138+
# called: a PR that moved is refused, and the ops tick dispatches again at its new head.
139139
- name: Check the checkout is at the head
140140
env:
141141
HEAD_SHA: ${{ inputs.head }}
@@ -169,7 +169,7 @@ jobs:
169169
DRY_RUN: ${{ inputs.dry_run && '1' || '0' }}
170170
run: node .redline/scripts/redline/fix.mjs
171171

172-
# fix.json goes up whatever the outcome; forge reads it to know why there is no bundle.
172+
# fix.json goes up whatever the outcome; the ops tick reads it to know why there is no bundle.
173173
- name: Upload the fix
174174
if: always()
175175
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2

‎.github/workflows/redline-fix.yml‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
# Redline fix: when Redline requests changes on a pull request here, forge dispatches this run
1+
# Redline fix: when Redline requests changes on a pull request here, the ops tick dispatches this run
22
# with the PR, the head Redline reviewed and the review. The fix itself is computed by
33
# askalf/ci (redline-fix-run.yml) on this repository's fix-lane runner and uploaded as
44
# the redline-fix artifact. Nothing here pushes or comments, and no token that could is on the
5-
# runner: forge verifies the artifact and pushes the fix to the PR branch with its own token.
5+
# runner: the ops tick verifies the artifact and pushes the fix to the PR branch with its own token.
66
name: Redline fix
77
run-name: Redline fix ${{ github.repository }}#${{ inputs.pr }} @ ${{ inputs.head }}
88

@@ -31,7 +31,7 @@ permissions:
3131
contents: read
3232
pull-requests: read
3333

34-
# No concurrency group: forge dispatches one run per review and reads each run's artifact, and
34+
# No concurrency group: the ops tick dispatches one run per review and reads each run's artifact, and
3535
# a group keeps only one pending run, so a third dispatch would cancel the second before it ran.
3636
# Runs need no serializing, since none of them pushes; they wait for the fix-lane runner in GitHub's
3737
# job queue, which cancels nothing.

‎.github/workflows/redline-pin-bump.yml‎

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
# Opens a PR in each Redline caller that moves its pins, and the redline-ref input that names the
2-
# same commit, to the main commit that changed the review or the fix. A caller pins two reusable
3-
# workflows by SHA: redline.yml calls redline-review.yml and redline-fix.yml, where the repository
4-
# has one, calls redline-fix-run.yml. A workflow pins this repository's actions as steps, in
2+
# same commit, to the main commit that changed the review or the fix. A caller pins its reusable
3+
# workflows by SHA: redline.yml calls redline-review.yml, and, where the repository has them,
4+
# redline-fix.yml calls redline-fix-run.yml, public-text.yml calls public-text.yml and
5+
# redline-post.yml calls redline-post-verdict.yml. A workflow pins this repository's actions as steps, in
56
# whichever workflow file it lives: uses: askalf/ci/actions/drift-report@<sha> (a watcher's report
67
# step), uses: askalf/ci/actions/checkout-with-retry@<sha> (any job's checkout), and
78
# uses: askalf/ci/actions/fleet-status@<sha> and fleet-status-check@<sha> (the fleet lanes).
@@ -72,15 +73,15 @@ jobs:
7273
# A bot-shaped branch opened by askalf: the fleet lanes treat it as a bot PR.
7374
BRANCH: bot/redline-pin
7475
# The review caller is in every repo but platform; the fix caller only where the fix lane is
75-
# wired, and the public-text caller where the dash check is, so a missing one is skipped, not
76-
# an error. A repository with neither is still a caller
76+
# wired, the public-text caller where the dash check is and the post caller where the verdict
77+
# posts from CI, so a missing one is skipped, not an error. A repository with neither is still a caller
7778
# when a workflow there pins one of this repository's actions, drift-report,
7879
# checkout-with-retry, fleet-status or fleet-status-check (platform, whose own CI gates it,
7980
# not Redline): it is bumped for those pins alone, and only a repository with no pin at all
8081
# is wrong.
8182
CALLER_PATHS: >-
8283
.github/workflows/redline.yml .github/workflows/redline-fix.yml
83-
.github/workflows/public-text.yml
84+
.github/workflows/public-text.yml .github/workflows/redline-post.yml
8485
# What a caller runs: the scripts the reusable workflows fetch, and the workflows. The tests,
8586
# their fixtures and the README change nothing a caller runs, so they move no pin; nor does
8687
# local.mjs, the pre-push review, which runs on a laptop and the runner host and in no
@@ -105,6 +106,7 @@ jobs:
105106
.github/workflows/redline-review.yml
106107
.github/workflows/redline-fix-run.yml
107108
.github/workflows/public-text.yml
109+
.github/workflows/redline-post-verdict.yml
108110
.github/workflows/redline-pin-bump.yml
109111
QUIET_MINUTES: 60
110112
WAVE_SIZE: 3
@@ -139,6 +141,7 @@ jobs:
139141
.github/workflows/redline-review.yml
140142
.github/workflows/redline-fix-run.yml
141143
.github/workflows/public-text.yml
144+
.github/workflows/redline-post-verdict.yml
142145
sparse-checkout-cone-mode: false
143146
persist-credentials: false
144147

@@ -245,7 +248,7 @@ jobs:
245248
pr="$(gh api "repos/${SOURCE}/commits/${SHA}/pulls" --jq '.[0].number // empty' || true)"
246249
note="main ${day}"
247250
if [ -n "$pr" ]; then note="${note}, ${SOURCE}#${pr}"; fi
248-
pattern="uses: ${SOURCE}/.github/workflows/(redline-review|redline-fix-run|public-text).yml@[0-9a-f]{40}"
251+
pattern="uses: ${SOURCE}/.github/workflows/(redline-review|redline-fix-run|public-text|redline-post-verdict).yml@[0-9a-f]{40}"
249252
title="ci: bump Redline to ${SOURCE}@${short}"
250253
body="Moves the pinned ${SOURCE} calls and their redline-ref inputs, and every ${SOURCE} action pin (drift-report, checkout-with-retry, fleet-status, fleet-status-check), to ${SOURCE}@${SHA}, the main commit that last changed the review, the fix or an action (${note}). The scripts are fetched at that same commit. The pins are the only change."
251254
@@ -295,6 +298,7 @@ jobs:
295298
case "$path" in
296299
*/redline-fix.yml) called=.github/workflows/redline-fix-run.yml ;;
297300
*/public-text.yml) called=.github/workflows/public-text.yml ;;
301+
*/redline-post.yml) called=.github/workflows/redline-post-verdict.yml ;;
298302
*) called=.github/workflows/redline-review.yml ;;
299303
esac
300304
# In this repository the called workflows sit beside its own callers, and public-text.yml
@@ -323,7 +327,7 @@ jobs:
323327
echo "::error::${repo}: ${path} does not grant $(printf '%s' "$missing" | paste -sd, -), which $(basename "$called") at ${short} asks for, so every run there fails at startup; grant it in ${path} first"
324328
bad=1; continue
325329
fi
326-
if grep -Eq "(redline-review|redline-fix-run|public-text).yml@${SHA}" <<< "$current" && grep -q "redline-ref: ${SHA}" <<< "$current"; then
330+
if grep -Eq "(redline-review|redline-fix-run|public-text|redline-post-verdict).yml@${SHA}" <<< "$current" && grep -q "redline-ref: ${SHA}" <<< "$current"; then
327331
echo "${path} already at ${short}"; continue
328332
fi
329333
todo+=("$path")
@@ -383,7 +387,7 @@ jobs:
383387
for path in "${todo[@]}"; do
384388
at="$(uri "$path")"
385389
if ! current="$(gh api "repos/${repo}/contents/${at}?ref=${BRANCH}" --jq .content 2>/dev/null | base64 -d)"; then carried=0; break; fi
386-
if ! grep -Eq "(redline-review|redline-fix-run|public-text).yml@${SHA}" <<< "$current" || ! grep -q "redline-ref: ${SHA}" <<< "$current"; then carried=0; break; fi
390+
if ! grep -Eq "(redline-review|redline-fix-run|public-text|redline-post-verdict).yml@${SHA}" <<< "$current" || ! grep -q "redline-ref: ${SHA}" <<< "$current"; then carried=0; break; fi
387391
done
388392
for path in "${atodo[@]}"; do
389393
at="$(uri "$path")"

‎.github/workflows/redline-review.yml‎

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,20 +4,21 @@
44
# credentials and its system prompt from files on the host, so no secret is stored in GitHub and
55
# the reviewer's rubric sits in no public repository.
66
# The finished review is uploaded as the redline-verdict artifact (verdict.json). When the host file
7-
# holds no reviewer token the review is not posted here: the forge posts it as sprayberry-redline
7+
# holds no reviewer token the review is not posted here: the ops tick, or the repository's own
8+
# redline-post.yml, posts it as sprayberry-redline
89
# only after checking, from the GitHub API, that the run came from the pinned redline.yml at the PR's
910
# current head and that the PR changes no workflow or action definitions.
1011
# The PR's code is checked out only to be read by the review's read-only tools; nothing from it runs.
1112
#
12-
# Dispatch mode: a caller's redline.yml also takes workflow_dispatch, and forge dispatches it on the
13+
# Dispatch mode: a caller's redline.yml also takes workflow_dispatch, and the ops tick dispatches it on the
1314
# default branch with the PR, the head to review and whether this is a re-read of a head already
1415
# reviewed. The run then executes the default branch's workflow files, not the PR's, so its verdict
15-
# holds even for a PR that changes CI definitions. Forge uses it for every head its pull_request run
16+
# holds even for a PR that changes CI definitions. The ops tick uses it for every head its pull_request run
1617
# cannot vouch for: a PR that changes CI, a verdict it refused, and a description-only re-read.
1718
# Fork PRs come here only in dispatch mode (operator, 2026-10-18). The pull_request path still refuses
1819
# a fork head before anything is fetched. On a dispatch the default branch's workflow files run, the
1920
# PR is read from the API, and the fork head is fetched by the repository's own pull ref, compared
20-
# with the sha forge named, and checked out with symlinks written as plain files. The review's tools
21+
# with the sha the ops tick named, and checked out with symlinks written as plain files. The review's tools
2122
# only list, read and search inside that checkout (review.mjs confines every path by its real path);
2223
# nothing from the head executes, and the job holds no credential that could write anywhere. A fork
2324
# PR whose workflows are still held at the contributor gate ("Approve and run") is not reviewed: the
@@ -109,7 +110,7 @@ jobs:
109110
process.exit(1);
110111
'
111112
112-
# A dispatch runs the default branch's workflow files, which is the only reason forge trusts
113+
# A dispatch runs the default branch's workflow files, which is the only reason the ops tick trusts
113114
# its verdict, so it must be a workflow_dispatch on the default branch. The PR it names must be
114115
# open, not a draft and at the head given. A head in a fork is allowed here, and only here:
115116
# the step says so in its `fork` output, and only once a job of a pull_request run for that
@@ -200,7 +201,7 @@ jobs:
200201

201202
# A fork head is fetched from this repository's own pull ref (GitHub mirrors every PR head
202203
# there), so nothing is read from the fork itself, and the fetched commit must be the sha
203-
# forge named. The checkout writes symlinks as plain files: a link pointing out of the
204+
# the ops tick named. The checkout writes symlinks as plain files: a link pointing out of the
204205
# checkout becomes text, and the review's tools refuse any path that resolves outside it
205206
# anyway. No hooks exist in a fresh repository, no submodule is fetched, nothing runs.
206207
- name: Fetch the fork head to read

‎.github/workflows/redline.yml‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
# Redline, the gating code review, as this repo's CI check. The review itself is this repo's own redline-review.yml, called at a pinned commit like every other caller does:
2-
# read-only tools, verdict = pass or fail. On pull_request it reviews same-repo PRs. Forge also
2+
# read-only tools, verdict = pass or fail. On pull_request it reviews same-repo PRs. The ops tick also
33
# dispatches it on the default branch for a head the pull_request run cannot vouch for (a PR that
4-
# changes CI, a verdict forge refused, a re-read after a description edit); that run executes the
4+
# changes CI, a verdict the ops tick refused, a re-read after a description edit); that run executes the
55
# default branch's workflow files, not the PR's, and reviews the head it is given.
66
name: Redline
7-
# Forge finds its dispatch by this title; keep it exact.
7+
# The ops tick finds its dispatch by this title; keep it exact.
88
run-name: ${{ github.event_name == 'workflow_dispatch' && format('Redline review {0}#{1} @ {2}{3}', github.repository, inputs.pr, inputs.head, inputs.reread && ' (re-read)' || '') || github.event.pull_request.title }}
99

1010
on:
@@ -35,7 +35,7 @@ permissions:
3535

3636
# On pull_request the newest push wins. A dispatch gets a group of its own per head and mode, and
3737
# is never cancelled: a group holds one pending run and a newer one cancels it, and a cancelled
38-
# dispatch leaves forge no verdict to read. Forge sends one dispatch per head and mode at a time.
38+
# dispatch leaves the ops tick no verdict to read. The ops tick sends one dispatch per head and mode at a time.
3939
concurrency:
4040
group: redline-${{ github.event_name }}-${{ github.event.pull_request.number || inputs.pr }}${{ inputs.head && format('-{0}-{1}', inputs.head, inputs.reread) || '' }}
4141
cancel-in-progress: ${{ github.event_name == 'pull_request' }}

‎README.md‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ full commit sha of `main`, so a change here reaches it only through a reviewed b
3636

3737
| This repository's own | What it does |
3838
|---|---|
39-
| `redline.yml`, `redline-fix.yml` | This repository's callers of the review and the fix, pinned and bumped like every other caller's. |
39+
| `redline.yml`, `redline-fix.yml`, `redline-post.yml` | This repository's callers of the review, the fix and the post, pinned and bumped like every other caller's. |
4040
| `redline-pin-bump.yml` | Hourly, moves every caller's pins to the newest `main` commit that changed what a caller runs, one pull request per repository. |
4141
| `redline-self-test.yml` | The Redline, public-text, drift-report, fleet-status and pin-bump tests on every pull request: a required check. |
4242
| `checkout-with-retry-self-test.yml` | Proves the retry action on a runner: a healthy checkout, the retry paths through a stub, and the act path under act. |
@@ -104,8 +104,8 @@ Next to the prompts the hosts hold the credential files the scripts read (`/etc/
104104
what a caller runs: the scripts the reusable workflows and actions fetch (their tests, test fixtures
105105
and READMEs aside), one of the four actions, or one of the reusable workflows. It rewrites, in every
106106
repository in its `CALLERS` list,
107-
the reusable-workflow pins in `redline.yml`, `redline-fix.yml` and `public-text.yml` where the
108-
repository has them, and every pin of one of the four actions in any workflow file there, through
107+
the reusable-workflow pins in `redline.yml`, `redline-fix.yml`, `public-text.yml` and
108+
`redline-post.yml` where the repository has them, and every pin of one of the four actions in any workflow file there, through
109109
`pin.mjs`: one commit per file on `bot/redline-pin`, one pull request per repository. Each
110110
repository's own gate reviews and merges the bump. This repository is in the list: its own callers
111111
move the same way. A repository with no pin of any kind is reported as wrong.

‎scripts/redline/README.md‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -81,12 +81,12 @@ through the API (no checkout) and fails when an added line, the title, the descr
8181
message carries an em or en dash, or when the title, the description or a commit message credits a
8282
model or an AI tool (a co-author trailer, a "generated with" footer, a session link), naming every
8383
one. Credits are read in that text only, since code and docs may name these tools for other
84-
reasons. Context and removed lines are never read, and captured data is skipped. It is a workflow of its own because forge posts a review only when the
84+
reasons. Context and removed lines are never read, and captured data is skipped. It is a workflow of its own because a review is posted only when the
8585
review run's conclusion agrees with the verdict.
8686

8787
## The fix: `redline-fix-run.yml` and `fix.mjs`
8888

89-
When a review requests changes, forge dispatches the repository's `.github/workflows/redline-fix.yml`
89+
When a review requests changes, the ops tick dispatches the repository's `.github/workflows/redline-fix.yml`
9090
(`workflow_dispatch`: `pr`, `head`, `review`, `dry_run`), which calls `redline-fix-run.yml` at the
9191
same pinned commit on `[self-hosted, <repo>-exec]`, the repository's non-root exec runner. The job
9292
checks that the checkout is exactly the reviewed head, then `fix.mjs`:
@@ -128,7 +128,7 @@ job killed at its 60-minute timeout still uploads a `fix.json` that says so. The
128128
`fixed`, and for `no_change` with `description: true` (the fix was a new description, which the
129129
caller applies); 1 for anything else. `fix-tools.json` is the fixer's `TOOLS` as a file, pinned in `truecopy.lock` like the
130130
reviewer's. The artifact is `redline-fix`. Nothing on the runner can push:
131-
forge verifies the artifact and pushes the commit to the PR branch with its own token, then
131+
the ops tick verifies the artifact and pushes the commit to the PR branch with its own token, then
132132
comments with the notes. The model is reached through a dario key socket named by `DARIO_SOCKET`
133133
in the env file, so no runner holds the key itself: the socket is the credential, and only the
134134
exec accounts can connect to it, never an account that runs untrusted code. `DARIO_API_KEY` in

0 commit comments

Comments
 (0)