@norskvideo/ctl-dev-kit 0.2.64 → 0.2.65

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/build/flake.nix CHANGED
@@ -13,7 +13,7 @@
13
13
  # integration) uses, so image builds never depend on the
14
14
  # ctl binary channel.
15
15
  #
16
- # The norsk-ctl pin below is bumped nightly by upgrade-latest; by hand with
16
+ # The norsk-ctl pin below is bumped nightly by bump.yml; by hand with
17
17
  # packages/dev-kit/build/refresh-ctl-pin.sh (writes ctlVersion + hashes)
18
18
  {
19
19
  description = "norsk-ctl product build + dev shell";
@@ -10,7 +10,7 @@
10
10
  # an sdk-app's dev loop is its own SDK app plus a Norsk engine, not a
11
11
  # ctl-launched product container. It still PINS one: `ctlVersion` below is the
12
12
  # norsk-ctl the product's CI tiers (smoke) launch it with, read from here so a
13
- # result belongs to a commit, and moved nightly by upgrade-latest. Decision: bun for tooling (install / build /
13
+ # result belongs to a commit, and moved nightly by bump.yml. Decision: bun for tooling (install / build /
14
14
  # test), Node for the shipped runtime (the SDK's blessed runtime).
15
15
  #
16
16
  # nixpkgs is pinned to the same rev the Studio flake uses, so bun matches the
@@ -29,7 +29,7 @@
29
29
 
30
30
  outputs = { self, nixpkgs, nixpkgs-biome }:
31
31
  let
32
- # The norsk-ctl CI runs (see above); upgrade-latest moves it to `latest`.
32
+ # The norsk-ctl CI runs (see above); bump.yml moves it to `latest`.
33
33
  ctlVersion = "0.1.0-2026-09-15-81bbde8";
34
34
  systems = [ "x86_64-linux" "aarch64-linux" "x86_64-darwin" "aarch64-darwin" ];
35
35
  forAllSystems = f: builtins.listToAttrs (map (s: { name = s; value = f s; }) systems);
@@ -36,4 +36,4 @@ done
36
36
 
37
37
  perl -0pi -e "s{(ctlVersion = \")[^\"]*(\")}{\${1}$ver\${2}}" "$flake"
38
38
  echo "updated $flake"
39
- echo "this is the starter's pin; each product's own flake.nix is bumped nightly by upgrade-latest"
39
+ echo "this is the starter's pin; each product's own flake.nix is bumped nightly by bump.yml"
@@ -79,17 +79,20 @@
79
79
  (`norsk-ctl serve`) + `norsk-ctl` on PATH (the nix shell) + `NORSK_LICENSE_FILE`.
80
80
  Anything the daemon can't see for you — a stored template, a rebuilt image — is
81
81
  stale until this loop re-runs; don't debug a ghost.
82
- - **The shared CI workflow is single-sourced too.** `.github/workflows/upgrade-latest.yml`
83
- is copied verbatim from `@norskvideo/ctl-dev-kit` (`conventions/upgrade-latest.yml`),
82
+ - **The shared CI workflows are single-sourced too.** `.github/workflows/bump.yml`
83
+ and the rest are copied verbatim from `@norskvideo/ctl-dev-kit` (`conventions/`),
84
84
  same as this core block and `nix/ctl-shell.nix`; `check:drift` fails CI if a copy
85
85
  diverges. Only the `product:` key is per-repo. Never hand-edit the copy — edit
86
86
  the dev-kit source and re-sync.
87
87
  - **CI runs the norsk-ctl this repo pins** (`flake.nix` `ctlVersion`), never S3's
88
- moving `latest`; only a `ctl-candidate` run tests a channel (`rc`). The bump bots
89
- (`upgrade-latest`, `sync-dev-kit`, `sync-ctl-packages`) never push to main: each
90
- opens a PR, and `bot-prs` merges it once checks, smoke, integration and the
91
- guides gate (build-image) are green on it. A red bot PR is the alarm for a bad
92
- upstream change; main stays green.
88
+ moving `latest`; only a `ctl-candidate` run tests a channel (`rc`). One nightly
89
+ bump, `bump.yml`, moves the dev-kit, the ctl-* and moq-* packages, and the
90
+ engine/Studio/norsk-ctl pins together, and never pushes to main: it opens one PR
91
+ on `bump/nightly`, and `bot-prs` merges it once checks, smoke, integration and
92
+ the guides gate (build-image) are green on it. A red bump PR is the alarm for a
93
+ bad upstream change, and names what moved; main stays green. To land the rest
94
+ without a bad component: `gh workflow run bump.yml -f components=<the others>`
95
+ (`dev-kit`, `ctl-packages`, `pins`).
93
96
  - **Flaky checks stay out of gates, never out of sight.** The guides gate runs
94
97
  the deterministic tiers; the engine tier runs beside it and reports (summary,
95
98
  warning, cell detail) without gating until norsk-ctl task 57 is fixed. A
@@ -1,13 +1,16 @@
1
- # Land the pin bots' green PRs; put the red ones on the product dashboard.
1
+ # Land the nightly bump's green PR; put a red one on the product dashboard.
2
2
  #
3
- # Three bots keep a product fresh: upgrade-latest (the Norsk nightly line and
4
- # the norsk-ctl pin), sync-dev-kit (this package) and sync-ctl-packages (the
5
- # ctl-* / moq-* npm family). All three ALWAYS open a PR and never push to main
6
- # (ci-workflows docs/dashboard/ci-fragility.md, proposal B): a bot's own gate
7
- # is lint, typecheck and unit tests, and the tiers that break on an upstream
8
- # change -- smoke, integration and the guides that gate build-image's publish
9
- # -- run on the PR. This workflow is what lands them. Nothing used to act on
10
- # those PRs: green
3
+ # One bot keeps a product fresh: bump.yml, which moves the dev-kit, the ctl-* /
4
+ # moq-* npm family, and the Norsk nightly pair and norsk-ctl pin in one run and
5
+ # opens one PR on bump/nightly (ci-workflows docs/dashboard/ci-fragility.md,
6
+ # proposal B2). It never pushes to main (proposal B): its own gate is lint,
7
+ # typecheck and unit tests, and the tiers that break on an upstream change --
8
+ # smoke, integration and the guides that gate build-image's publish -- run on
9
+ # the PR. This workflow is what lands it. Until bump.yml, three bots did that
10
+ # job, each with its own branch (upgrade-latest/*, sync-dev-kit/*,
11
+ # chore/sync-ctl-packages); those are still triaged, so their PRs still in
12
+ # flight when a product moves to bump.yml land or are reported like any other.
13
+ # Nothing used to act on bot PRs: green
11
14
  # ones sat unmerged (studio's ctl-sdk was twenty releases behind on 2026-10-03,
12
15
  # its PR open since 09-03) and red ones were invisible, because the bot that
13
16
  # opened them reports success. With a product count that only goes up, "someone
@@ -23,8 +26,9 @@
23
26
  # push alone cannot gate, and still runs on main after the merge. "Nothing
24
27
  # failed yet" is not enough: a slow tier that has not started has no check
25
28
  # run at all, so bot-prs used to merge before integration had begun;
26
- # - it conflicts with main -> re-run the bot that owns the branch, ONCE per
27
- # head, so it rebuilds the branch from today's main (see below);
29
+ # - it conflicts with main -> re-run bump.yml, ONCE per head, so it rebuilds
30
+ # the night from today's main (see below). Asked FIRST, whatever its
31
+ # checks say: the rebuild re-runs them all on the new base;
28
32
  # - a check failed, it still conflicts after that rebuild, or it is a draft
29
33
  # (the bot's own gate was red) -> list it, and report this repo's `bot-prs`
30
34
  # cell RED on the product dashboard, which is the Discord message people
@@ -34,24 +38,30 @@
34
38
  # workflow is broken, or does not run on PRs), so that is red too.
35
39
  # The cell goes green again once nothing is red.
36
40
  #
37
- # Why the conflict rebuild: the three bots fire within minutes of each other
38
- # each morning and all write package.json and bun.lock, each from main as it
39
- # stood. Whichever lands first leaves the other's open PR conflicting, and the
40
- # bot only rebuilds its branch on its next DAILY run -- so on 2026-10-09
41
- # commentary, probe and reuters each had a sync-ctl-packages PR "needing a
42
- # human" that a re-run of sync-ctl-packages fixed outright. Every bot rebuilds
43
- # from main when run: each force-pushes its branch from today's main and
44
- # closes any older PR of its own family. The marker comment caps it at one
41
+ # Why the conflict rebuild: when the three bots fired within minutes of each
42
+ # other, each writing package.json and bun.lock from main as it stood,
43
+ # whichever landed first left the others conflicting, and a bot rebuilt its
44
+ # branch only on its next DAILY run (2026-10-09: commentary, probe and reuters
45
+ # each had a sync-ctl-packages PR "needing a human" that a re-run fixed). One
46
+ # bump ends that, but a human's merge to main can still make bump/nightly
47
+ # conflict. bump.yml rebuilds from main when run: it force-pushes bump/nightly
48
+ # from today's main and closes any older bump PR, and an old bot's PR for each
49
+ # component it moved -- so it is the rebuild for those branches too, whose own
50
+ # workflows the move to bump.yml deleted. The marker comment caps it at one
45
51
  # rebuild per head, so a rebuild that still conflicts goes to a human instead
46
52
  # of looping every hour.
47
53
  #
54
+ # It triages the bot PRs that target one base: main, unless a dispatch names
55
+ # another (`base`). A trial of a dev-kit change against a throwaway branch is
56
+ # triaged, rebuilt and merged there, never on main, and reports nothing.
57
+ #
48
58
  # Runs when any gating tier finishes (the prompt path), hourly as a sweep,
49
59
  # and on demand. No checkout: it only talks to the GitHub API, so it needs none
50
60
  # of the runner-workspace steps the building workflows carry.
51
61
  #
52
62
  # Single-sourced in @norskvideo/ctl-dev-kit (conventions/bot-prs.yml) and copied
53
63
  # verbatim into each product repo -- it reads its dashboard key from this repo's
54
- # upgrade-latest.yml rather than carrying one -- so sync-drift creates it where
64
+ # bump.yml rather than carrying one -- so sync-drift creates it where
55
65
  # absent and check:drift fails a copy that diverges. Never hand-edit the copy.
56
66
  name: bot-prs
57
67
 
@@ -62,6 +72,10 @@ on:
62
72
  schedule:
63
73
  - cron: "23 * * * *"
64
74
  workflow_dispatch:
75
+ inputs:
76
+ base:
77
+ description: "Triage the bot PRs that target this branch. main, unless trialling on a throwaway branch."
78
+ default: main
65
79
 
66
80
  permissions:
67
81
  contents: read
@@ -96,6 +110,7 @@ jobs:
96
110
  READ_TOKEN: ${{ github.token }}
97
111
  WRITE_TOKEN: ${{ secrets.CI_DISPATCH_TOKEN }}
98
112
  REPO: ${{ github.repository }}
113
+ BASE: ${{ inputs.base || 'main' }}
99
114
  run: |
100
115
  set -euo pipefail
101
116
  api="https://api.github.com/repos/$REPO"
@@ -114,12 +129,14 @@ jobs:
114
129
  exit 1
115
130
  }
116
131
 
117
- # The bots own exactly these branches (see each workflow's PR step).
132
+ # The bump owns bump/nightly (see bump.yml's PR step); the other three
133
+ # are the retired bots' branches, still landed while in flight.
118
134
  pulls="$(gh_api "$api/pulls?state=open&per_page=100")"
119
135
  expect "listing open PRs" 'type == "array"' "$pulls"
120
- prs="$(jq -c --arg repo "$REPO" '
136
+ prs="$(jq -c --arg repo "$REPO" --arg base "$BASE" '
121
137
  [.[] | select(.head.repo.full_name == $repo)
122
- | select(.head.ref | test("^(upgrade-latest/|sync-dev-kit/|chore/sync-ctl-packages$)"))
138
+ | select(.base.ref == $base)
139
+ | select(.head.ref | test("^(bump/nightly$|upgrade-latest/|sync-dev-kit/|chore/sync-ctl-packages$)"))
123
140
  | {number, ref: .head.ref, sha: .head.sha, draft, url: .html_url}]' <<<"$pulls")"
124
141
 
125
142
  # Does this workflow (on stdin) run on pull_request? Only its `on:` block
@@ -204,12 +221,12 @@ jobs:
204
221
  fi
205
222
  }
206
223
 
207
- # The workflow that owns each bot branch, i.e. the one that rebuilds it.
224
+ # The workflow that rebuilds each bot branch: bump.yml, for the retired
225
+ # bots' branches too (their workflows went when bump.yml arrived, and
226
+ # bump.yml supersedes their PRs for every component it moves).
208
227
  producer() {
209
228
  case "$1" in
210
- upgrade-latest/*) echo upgrade-latest.yml ;;
211
- sync-dev-kit/*) echo sync-dev-kit.yml ;;
212
- chore/sync-ctl-packages) echo sync-ctl-packages.yml ;;
229
+ bump/nightly | upgrade-latest/* | sync-dev-kit/* | chore/sync-ctl-packages) echo bump.yml ;;
213
230
  *) echo "" ;;
214
231
  esac
215
232
  }
@@ -220,31 +237,14 @@ jobs:
220
237
  while IFS= read -r pr; do
221
238
  [ -n "$pr" ] || continue
222
239
  n="$(jq -r .number <<<"$pr")"; ref="$(jq -r .ref <<<"$pr")"; sha="$(jq -r .sha <<<"$pr")"
223
- runs="$(gh_api "$api/commits/$sha/check-runs?per_page=100")"
224
- expect "reading checks for #$n" '.check_runs | type == "array"' "$runs"
225
- failed="$(jq -r '[.check_runs[] | select(.conclusion | IN("failure","cancelled","timed_out","action_required","startup_failure")) | .name] | unique | join(", ")' <<<"$runs")"
226
- pending="$(jq -r '[.check_runs[] | select(.status != "completed")] | length' <<<"$runs")"
227
- passed="$(jq -r '[.check_runs[] | select(.conclusion == "success")] | length' <<<"$runs")"
228
- if [ -n "$failed" ]; then red+=("#$n $ref: failing $failed"); continue; fi
229
- if [ "$(jq -r .draft <<<"$pr")" = "true" ]; then red+=("#$n $ref: draft (its bot's gate was red)"); continue; fi
230
- if [ "$pending" -gt 0 ] || [ "$passed" -eq 0 ]; then echo "#$n $ref: checks not finished; next time"; continue; fi
231
- # Every tier that runs on a bot PR must have PASSED on this head.
232
- required="$(tiers_for "$sha")"
233
- wf_runs="$(gh_api "$api/actions/runs?head_sha=$sha&per_page=100")"
234
- expect "reading workflow runs for #$n" '.workflow_runs | type == "array"' "$wf_runs"
235
- verdict="$(tier_verdict "$required" "$wf_runs" "$(date +%s)")"
236
- case "$verdict" in
237
- ok) ;;
238
- red\ *) red+=("#$n $ref: ${verdict#red }"); continue ;;
239
- rerun\ *)
240
- for id in ${verdict#rerun }; do
241
- code="$(gh_actions -o /dev/null -w '%{http_code}' -X POST "$api/actions/runs/$id/rerun")"
242
- echo "#$n $ref: a gating tier (run $id) was cancelled; re-running it (HTTP $code)"
243
- done
244
- continue ;;
245
- *) echo "#$n $ref: ${verdict#wait }; next time"; continue ;;
246
- esac
247
- # GitHub computes mergeability lazily; ask until it has an answer.
240
+ # Mergeability FIRST, before the checks are judged. A rebuild re-runs
241
+ # every tier on today's base, so a conflicting PR is rebuilt whatever
242
+ # its checks say: relay #11 (2026-10-10) carried a smoke failure from
243
+ # before main moved, was reported red for it, and sat conflicting
244
+ # for 90 minutes with its rebuild never asked for. Only a PR that
245
+ # still conflicts after its rebuild, or merges cleanly with red
246
+ # checks, is red. GitHub computes mergeability lazily; ask until it
247
+ # has an answer.
248
248
  mergeable=null
249
249
  for _ in 1 2 3 4 5; do
250
250
  mergeable="$(gh_api "$api/pulls/$n" | jq -r .mergeable)"
@@ -262,9 +262,9 @@ jobs:
262
262
  elif jq -e --arg m "$marker" 'any(.[]; .body | contains($m))' >/dev/null <<<"$comments"; then
263
263
  red+=("#$n $ref: still does not merge cleanly with main after $wf rebuilt it")
264
264
  else
265
- code="$(gh_actions -o /dev/null -w '%{http_code}' -X POST "$api/actions/workflows/$wf/dispatches" -d '{"ref":"main"}')"
265
+ code="$(gh_actions -o /dev/null -w '%{http_code}' -X POST "$api/actions/workflows/$wf/dispatches" -d "$(jq -nc --arg b "$BASE" '{ref:$b, inputs:{base:$b}}')")"
266
266
  if [ "$code" = "204" ]; then
267
- body="$marker -- it conflicted with main (another bot landed first), so $wf was re-run to rebuild it from today's main. If the rebuilt branch conflicts too, this PR is reported for a human."
267
+ body="$marker -- it conflicted with $BASE, so $wf was re-run to rebuild the bump from today's $BASE. If the rebuilt branch conflicts too, this PR is reported for a human."
268
268
  gh_write -o /dev/null -X POST "$api/issues/$n/comments" -d "$(jq -nc --arg b "$body" '{body:$b}')" || true
269
269
  rebuilt+=("#$n")
270
270
  echo "#$n $ref: conflicts with main; re-ran $wf to rebuild it"
@@ -274,6 +274,30 @@ jobs:
274
274
  fi
275
275
  continue
276
276
  fi
277
+ runs="$(gh_api "$api/commits/$sha/check-runs?per_page=100")"
278
+ expect "reading checks for #$n" '.check_runs | type == "array"' "$runs"
279
+ failed="$(jq -r '[.check_runs[] | select(.conclusion | IN("failure","cancelled","timed_out","action_required","startup_failure")) | .name] | unique | join(", ")' <<<"$runs")"
280
+ pending="$(jq -r '[.check_runs[] | select(.status != "completed")] | length' <<<"$runs")"
281
+ passed="$(jq -r '[.check_runs[] | select(.conclusion == "success")] | length' <<<"$runs")"
282
+ if [ -n "$failed" ]; then red+=("#$n $ref: failing $failed"); continue; fi
283
+ if [ "$(jq -r .draft <<<"$pr")" = "true" ]; then red+=("#$n $ref: draft (its bot's gate was red)"); continue; fi
284
+ if [ "$pending" -gt 0 ] || [ "$passed" -eq 0 ]; then echo "#$n $ref: checks not finished; next time"; continue; fi
285
+ # Every tier that runs on a bot PR must have PASSED on this head.
286
+ required="$(tiers_for "$sha")"
287
+ wf_runs="$(gh_api "$api/actions/runs?head_sha=$sha&per_page=100")"
288
+ expect "reading workflow runs for #$n" '.workflow_runs | type == "array"' "$wf_runs"
289
+ verdict="$(tier_verdict "$required" "$wf_runs" "$(date +%s)")"
290
+ case "$verdict" in
291
+ ok) ;;
292
+ red\ *) red+=("#$n $ref: ${verdict#red }"); continue ;;
293
+ rerun\ *)
294
+ for id in ${verdict#rerun }; do
295
+ code="$(gh_actions -o /dev/null -w '%{http_code}' -X POST "$api/actions/runs/$id/rerun")"
296
+ echo "#$n $ref: a gating tier (run $id) was cancelled; re-running it (HTTP $code)"
297
+ done
298
+ continue ;;
299
+ *) echo "#$n $ref: ${verdict#wait }; next time"; continue ;;
300
+ esac
277
301
  # sha pins the merge to what was checked: a bot force-pushing the
278
302
  # branch meanwhile makes this refuse rather than land unchecked code.
279
303
  res="$(gh_write -X PUT "$api/pulls/$n/merge" -d "$(jq -nc --arg sha "$sha" '{merge_method:"squash", sha:$sha}')")"
@@ -304,7 +328,8 @@ jobs:
304
328
 
305
329
  - name: Report to the product dashboard
306
330
  # Always: a triage that broke is exactly what nobody would otherwise see.
307
- if: always()
331
+ # But only for main: a trial against another base must not paint the board.
332
+ if: always() && (inputs.base || 'main') == 'main'
308
333
  env:
309
334
  TOKEN: ${{ secrets.CI_DISPATCH_TOKEN }}
310
335
  READ_TOKEN: ${{ github.token }}
@@ -317,13 +342,18 @@ jobs:
317
342
  REPO: ${{ github.repository }}
318
343
  run: |
319
344
  set -euo pipefail
320
- # The dashboard key is the one upgrade-latest.yml reports under, read
321
- # from it so this file can stay byte-identical across products.
322
- product="$(curl -sS -H "Authorization: Bearer $READ_TOKEN" -H "Accept: application/vnd.github.raw" \
323
- "https://api.github.com/repos/$REPO/contents/.github/workflows/upgrade-latest.yml" \
324
- | sed -nE 's/^[[:space:]]*product:[[:space:]]*([^[:space:]]+).*/\1/p' | head -1)"
345
+ # The dashboard key is the one bump.yml reports under, read from it so
346
+ # this file can stay byte-identical across products; upgrade-latest.yml
347
+ # carried it before bump.yml did. -f: a 404 must not read as a key.
348
+ product=""
349
+ for wf in bump.yml upgrade-latest.yml; do
350
+ product="$(curl -fsS -H "Authorization: Bearer $READ_TOKEN" -H "Accept: application/vnd.github.raw" \
351
+ "https://api.github.com/repos/$REPO/contents/.github/workflows/$wf" 2>/dev/null \
352
+ | sed -nE 's/^[[:space:]]*product:[[:space:]]*([^[:space:]]+).*/\1/p' | head -1 || true)"
353
+ [ -z "$product" ] || break
354
+ done
325
355
  if [ -z "$product" ] || [ "$product" = "__PRODUCT__" ]; then
326
- echo "::warning::no product key in upgrade-latest.yml; not reporting to the dashboard"
356
+ echo "::warning::no product key in bump.yml; not reporting to the dashboard"
327
357
  exit 0
328
358
  fi
329
359
  ts="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
@@ -190,14 +190,14 @@ jobs:
190
190
  done <<<"$left"
191
191
 
192
192
  # The norsk-ctl this commit pins (flake.nix ctlVersion, moved by
193
- # upgrade-latest's bump PR), never S3's moving `latest`: a guide run is then
193
+ # bump.yml's nightly PR), never S3's moving `latest`: a guide run is then
194
194
  # a real repeat, and a red belongs to a commit (ci-fragility proposal A).
195
195
  - name: Download the pinned norsk-ctl binary (flake.nix ctlVersion)
196
196
  run: |
197
197
  set -euo pipefail
198
198
  S3="https://s3.eu-west-1.amazonaws.com/norsk.video/norsk-ctl"
199
199
  ver="$( { sed -nE 's/^[[:space:]]*ctlVersion = "([^"]+)";.*/\1/p' flake.nix 2>/dev/null || true; } | head -1)"
200
- [ -n "$ver" ] || { echo "::error::flake.nix pins no ctlVersion. CI runs the norsk-ctl this commit pins (upgrade-latest moves it); add ctlVersion = \"<version>\"; to flake.nix."; exit 1; }
200
+ [ -n "$ver" ] || { echo "::error::flake.nix pins no ctlVersion. CI runs the norsk-ctl this commit pins (the nightly bump.yml moves it); add ctlVersion = \"<version>\"; to flake.nix."; exit 1; }
201
201
  echo "norsk-ctl pinned by flake.nix ctlVersion -> $ver"
202
202
  curl -fsSL --retry 3 --retry-all-errors --retry-delay 2 "$S3/$ver/norsk-ctl-$ver-linux-x64" -o "$RUNNER_TEMP/norsk-ctl"
203
203
  chmod +x "$RUNNER_TEMP/norsk-ctl"
@@ -21,8 +21,9 @@
21
21
  # (rc -> latest promotion) lands, flip the push default to `nightly` and let the
22
22
  # promotion gate move `latest`.
23
23
  #
24
- # BOT PRs: on a pull request from a bot branch (upgrade-latest/*,
25
- # sync-dev-kit/*, chore/sync-ctl-packages) the workflow builds both arches and
24
+ # BOT PRs: on a pull request from a bot branch (bump/nightly, and the retired
25
+ # bots' upgrade-latest/*, sync-dev-kit/* and chore/sync-ctl-packages, which the
26
+ # PR that brings bump.yml rides on) the workflow builds both arches and
26
27
  # runs the guides gate exactly as a push would (the deterministic tiers gate;
27
28
  # the engine tier reports beside it), and publishes, records and
28
29
  # reports nothing. A bump reaches main only once that has passed on it, and
@@ -69,7 +70,7 @@ jobs:
69
70
  # Compute the immutable label ONCE, so both arch builds and the manifest share
70
71
  # it (a per-job `date` could straddle midnight and disagree).
71
72
  label:
72
- if: ${{ github.event_name != 'pull_request' || (github.event.pull_request.head.repo.full_name == github.repository && (startsWith(github.head_ref, 'upgrade-latest/') || startsWith(github.head_ref, 'sync-dev-kit/') || github.head_ref == 'chore/sync-ctl-packages')) }}
73
+ if: ${{ github.event_name != 'pull_request' || (github.event.pull_request.head.repo.full_name == github.repository && (github.head_ref == 'bump/nightly' || startsWith(github.head_ref, 'upgrade-latest/') || startsWith(github.head_ref, 'sync-dev-kit/') || github.head_ref == 'chore/sync-ctl-packages')) }}
73
74
  runs-on: x64
74
75
  outputs:
75
76
  label: ${{ steps.gen.outputs.label }}
@@ -430,7 +431,7 @@ jobs:
430
431
  done <<<"$left"
431
432
 
432
433
  # The norsk-ctl this commit pins (flake.nix ctlVersion, moved by
433
- # upgrade-latest's bump PR), never S3's moving `latest`: a guide run is then
434
+ # bump.yml's nightly PR), never S3's moving `latest`: a guide run is then
434
435
  # a real repeat, and a red belongs to a commit (ci-fragility proposal A).
435
436
  - name: Download the pinned norsk-ctl binary (flake.nix ctlVersion)
436
437
  if: ${{ steps.plan.outputs.guides == 'run' }}
@@ -438,7 +439,7 @@ jobs:
438
439
  set -euo pipefail
439
440
  S3="https://s3.eu-west-1.amazonaws.com/norsk.video/norsk-ctl"
440
441
  ver="$( { sed -nE 's/^[[:space:]]*ctlVersion = "([^"]+)";.*/\1/p' flake.nix 2>/dev/null || true; } | head -1)"
441
- [ -n "$ver" ] || { echo "::error::flake.nix pins no ctlVersion. CI runs the norsk-ctl this commit pins (upgrade-latest moves it); add ctlVersion = \"<version>\"; to flake.nix."; exit 1; }
442
+ [ -n "$ver" ] || { echo "::error::flake.nix pins no ctlVersion. CI runs the norsk-ctl this commit pins (the nightly bump.yml moves it); add ctlVersion = \"<version>\"; to flake.nix."; exit 1; }
442
443
  echo "norsk-ctl pinned by flake.nix ctlVersion -> $ver"
443
444
  curl -fsSL --retry 3 --retry-all-errors --retry-delay 2 "$S3/$ver/norsk-ctl-$ver-linux-x64" -o "$RUNNER_TEMP/norsk-ctl"
444
445
  chmod +x "$RUNNER_TEMP/norsk-ctl"
@@ -630,14 +631,14 @@ jobs:
630
631
  done <<<"$left"
631
632
 
632
633
  # The norsk-ctl this commit pins (flake.nix ctlVersion, moved by
633
- # upgrade-latest's bump PR), never S3's moving `latest`: a guide run is then
634
+ # bump.yml's nightly PR), never S3's moving `latest`: a guide run is then
634
635
  # a real repeat, and a red belongs to a commit (ci-fragility proposal A).
635
636
  - name: Download the pinned norsk-ctl binary (flake.nix ctlVersion)
636
637
  run: |
637
638
  set -euo pipefail
638
639
  S3="https://s3.eu-west-1.amazonaws.com/norsk.video/norsk-ctl"
639
640
  ver="$( { sed -nE 's/^[[:space:]]*ctlVersion = "([^"]+)";.*/\1/p' flake.nix 2>/dev/null || true; } | head -1)"
640
- [ -n "$ver" ] || { echo "::error::flake.nix pins no ctlVersion. CI runs the norsk-ctl this commit pins (upgrade-latest moves it); add ctlVersion = \"<version>\"; to flake.nix."; exit 1; }
641
+ [ -n "$ver" ] || { echo "::error::flake.nix pins no ctlVersion. CI runs the norsk-ctl this commit pins (the nightly bump.yml moves it); add ctlVersion = \"<version>\"; to flake.nix."; exit 1; }
641
642
  echo "norsk-ctl pinned by flake.nix ctlVersion -> $ver"
642
643
  curl -fsSL --retry 3 --retry-all-errors --retry-delay 2 "$S3/$ver/norsk-ctl-$ver-linux-x64" -o "$RUNNER_TEMP/norsk-ctl"
643
644
  chmod +x "$RUNNER_TEMP/norsk-ctl"