@norskvideo/ctl-dev-kit 0.1.84 → 0.1.86

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.
@@ -52,17 +52,61 @@ jobs:
52
52
  - runner: '["ar-arm-vm"]'
53
53
  runs-on: ${{ fromJSON(matrix.runner) }}
54
54
  steps:
55
- # BEFORE checkout: launched instances leave root-owned bind-mount target
56
- # dirs under test-temp/ that the non-root runner user cannot remove, so
57
- # actions/checkout's own cleanup would fail the job before anything runs.
58
- # Nuke them from a throwaway root container first. Best-effort.
59
- - name: Clear stale root-owned test-temp (pre-checkout)
55
+ # Runs BEFORE checkout, and does two things: points the harness's temp base
56
+ # out of the workspace for every later step in this job, and clears whatever
57
+ # the old repo-local default left behind on this runner. The body carries the
58
+ # why. It fails the job only when legacy litter survives -- which would take
59
+ # the checkout down a step later anyway, but report nothing useful.
60
+ - name: Route test-temp out of the workspace (pre-checkout)
60
61
  run: |
61
62
  set -uo pipefail
63
+ # These runners are docker-OUTSIDE-of-docker, so a bind-mount source the
64
+ # HOST daemon has not seen before is created by dockerd, as ROOT, on the
65
+ # host -- even when the launch passes --container-user (reproduced
66
+ # 2026-09-04). The harness's default base is repo-local for an OrbStack
67
+ # inotify constraint that binds macOS dev and nothing here, so every run
68
+ # seeded the CHECKOUT with root-owned dirs a non-root `git clean -ffdx`
69
+ # cannot remove. That took commentary's checks AND integration red on
70
+ # 2026-09-03. Use the sanctioned override, per-run and outside the
71
+ # checkout -- as 8ff17a8d did in June for one debug workflow, and stopped.
72
+ base="$RUNNER_TEMP/nctt-$GITHUB_RUN_ID-$GITHUB_RUN_ATTEMPT"
73
+ mkdir -p "$base"
74
+ echo "NORSK_CTL_TEST_TMP=$base" >> "$GITHUB_ENV"
75
+ # Yesterday's bases hold dockerd-created root dirs, so a non-root rm
76
+ # EACCESes. They cannot wedge a checkout, but they do fill the disk.
77
+ for old in $(find "$RUNNER_TEMP" -maxdepth 1 -name 'nctt-*' -mtime +0 -printf '%f\n' 2>/dev/null || true); do
78
+ docker run --rm --user 0:0 -v "$RUNNER_TEMP":/t alpine sh -c 'rm -rf -- "/t/$1"' sh "$old" >/dev/null 2>&1 || true
79
+ done
80
+ # LEGACY: a runner that ran the old default still carries a workspace
81
+ # test-temp, and a checkout with clean:true dies on it. Reap the holders
82
+ # first -- rm cannot unlink a live mountpoint even as root (EBUSY), and a
83
+ # RESTARTING leaked container re-creates the path as root seconds after
84
+ # any clean. Match on mount SOURCE, not a label: the holders are untracked
85
+ # by construction, because a killed run labels nothing.
62
86
  tt="$GITHUB_WORKSPACE/test-temp"
63
87
  [ -d "$tt" ] || exit 0
64
- docker run --rm --user 0:0 -v "$tt":/t alpine sh \
65
- -c 'rm -rf /t/* /t/.[!.]* 2>/dev/null || true' || rm -rf "$tt"/* 2>/dev/null || true
88
+ stuck=""
89
+ for c in $(docker ps -aq 2>/dev/null || true); do
90
+ if docker inspect -f '{{range .Mounts}}{{println .Source}}{{end}}' "$c" 2>/dev/null | grep -q "^$tt/"; then
91
+ stuck="$stuck $c"
92
+ fi
93
+ done
94
+ if [ -n "$stuck" ]; then
95
+ echo "reaping containers holding mounts under $tt:$stuck"
96
+ docker rm -f $stuck || true
97
+ fi
98
+ # The DIRECTORY, not just its contents: an empty but root-owned base
99
+ # still EACCESes a later mkdtemp. Mounting the PARENT is what lets a root
100
+ # container unlink the leaf.
101
+ docker run --rm --user 0:0 -v "$GITHUB_WORKSPACE":/w alpine \
102
+ sh -c 'rm -rf /w/test-temp' || rm -rf "$tt" || true
103
+ # Fail HERE if it survived. The checkout fails on it either way, but
104
+ # reports only an EACCES rmdir with no clue what was holding the path.
105
+ if [ -e "$tt" ]; then
106
+ echo "::error::$tt survived the pre-checkout clean"
107
+ ls -lan "$tt" || true
108
+ exit 1
109
+ fi
66
110
 
67
111
  - uses: actions/checkout@v5
68
112
  with:
@@ -246,16 +290,61 @@ jobs:
246
290
  if: ${{ !cancelled() && github.event_name != 'repository_dispatch' }}
247
291
  runs-on: x64
248
292
  steps:
249
- # Same reason as the first checkout in this file: clear root-owned leftovers
250
- # from a root container so the checkout below can clean properly. Best-effort
251
- # by construction -- no docker, no test-temp, or a failed run all fall through.
252
- - name: Clear stale root-owned test-temp (pre-checkout)
293
+ # Runs BEFORE checkout, and does two things: points the harness's temp base
294
+ # out of the workspace for every later step in this job, and clears whatever
295
+ # the old repo-local default left behind on this runner. The body carries the
296
+ # why. It fails the job only when legacy litter survives -- which would take
297
+ # the checkout down a step later anyway, but report nothing useful.
298
+ - name: Route test-temp out of the workspace (pre-checkout)
253
299
  run: |
254
300
  set -uo pipefail
301
+ # These runners are docker-OUTSIDE-of-docker, so a bind-mount source the
302
+ # HOST daemon has not seen before is created by dockerd, as ROOT, on the
303
+ # host -- even when the launch passes --container-user (reproduced
304
+ # 2026-09-04). The harness's default base is repo-local for an OrbStack
305
+ # inotify constraint that binds macOS dev and nothing here, so every run
306
+ # seeded the CHECKOUT with root-owned dirs a non-root `git clean -ffdx`
307
+ # cannot remove. That took commentary's checks AND integration red on
308
+ # 2026-09-03. Use the sanctioned override, per-run and outside the
309
+ # checkout -- as 8ff17a8d did in June for one debug workflow, and stopped.
310
+ base="$RUNNER_TEMP/nctt-$GITHUB_RUN_ID-$GITHUB_RUN_ATTEMPT"
311
+ mkdir -p "$base"
312
+ echo "NORSK_CTL_TEST_TMP=$base" >> "$GITHUB_ENV"
313
+ # Yesterday's bases hold dockerd-created root dirs, so a non-root rm
314
+ # EACCESes. They cannot wedge a checkout, but they do fill the disk.
315
+ for old in $(find "$RUNNER_TEMP" -maxdepth 1 -name 'nctt-*' -mtime +0 -printf '%f\n' 2>/dev/null || true); do
316
+ docker run --rm --user 0:0 -v "$RUNNER_TEMP":/t alpine sh -c 'rm -rf -- "/t/$1"' sh "$old" >/dev/null 2>&1 || true
317
+ done
318
+ # LEGACY: a runner that ran the old default still carries a workspace
319
+ # test-temp, and a checkout with clean:true dies on it. Reap the holders
320
+ # first -- rm cannot unlink a live mountpoint even as root (EBUSY), and a
321
+ # RESTARTING leaked container re-creates the path as root seconds after
322
+ # any clean. Match on mount SOURCE, not a label: the holders are untracked
323
+ # by construction, because a killed run labels nothing.
255
324
  tt="$GITHUB_WORKSPACE/test-temp"
256
325
  [ -d "$tt" ] || exit 0
257
- docker run --rm --user 0:0 -v "$tt":/t alpine sh \
258
- -c 'rm -rf /t/* /t/.[!.]* 2>/dev/null || true' || rm -rf "$tt"/* 2>/dev/null || true
326
+ stuck=""
327
+ for c in $(docker ps -aq 2>/dev/null || true); do
328
+ if docker inspect -f '{{range .Mounts}}{{println .Source}}{{end}}' "$c" 2>/dev/null | grep -q "^$tt/"; then
329
+ stuck="$stuck $c"
330
+ fi
331
+ done
332
+ if [ -n "$stuck" ]; then
333
+ echo "reaping containers holding mounts under $tt:$stuck"
334
+ docker rm -f $stuck || true
335
+ fi
336
+ # The DIRECTORY, not just its contents: an empty but root-owned base
337
+ # still EACCESes a later mkdtemp. Mounting the PARENT is what lets a root
338
+ # container unlink the leaf.
339
+ docker run --rm --user 0:0 -v "$GITHUB_WORKSPACE":/w alpine \
340
+ sh -c 'rm -rf /w/test-temp' || rm -rf "$tt" || true
341
+ # Fail HERE if it survived. The checkout fails on it either way, but
342
+ # reports only an EACCES rmdir with no clue what was holding the path.
343
+ if [ -e "$tt" ]; then
344
+ echo "::error::$tt survived the pre-checkout clean"
345
+ ls -lan "$tt" || true
346
+ exit 1
347
+ fi
259
348
 
260
349
  - uses: actions/checkout@v5
261
350
  with:
@@ -41,23 +41,61 @@ jobs:
41
41
  sync:
42
42
  runs-on: x64
43
43
  steps:
44
- # Root-owned leftovers under test-temp/ are what `clean: false` used to route
45
- # around: the integration suite bind-mounts host dirs into containers, and a
46
- # non-root git clean then EACCESes on what they wrote -- taking down whatever
47
- # innocent job checked out next. Skipping the clean cured that symptom and
48
- # caused another: every gitignored artifact survived between runs, so a test
49
- # could pass on build output an earlier job left behind and go red the first
50
- # time it landed on a cold runner (probe, 2026-09-01). Clear the leftovers
51
- # from a root container FIRST, and the checkout can clean properly again.
52
- # Best-effort by construction: no docker, no test-temp, or a failed run all
53
- # fall through without failing the job.
54
- - name: Clear stale root-owned test-temp (pre-checkout)
44
+ # Runs BEFORE checkout, and does two things: points the harness's temp base
45
+ # out of the workspace for every later step in this job, and clears whatever
46
+ # the old repo-local default left behind on this runner. The body carries the
47
+ # why. It fails the job only when legacy litter survives -- which would take
48
+ # the checkout down a step later anyway, but report nothing useful.
49
+ - name: Route test-temp out of the workspace (pre-checkout)
55
50
  run: |
56
51
  set -uo pipefail
52
+ # These runners are docker-OUTSIDE-of-docker, so a bind-mount source the
53
+ # HOST daemon has not seen before is created by dockerd, as ROOT, on the
54
+ # host -- even when the launch passes --container-user (reproduced
55
+ # 2026-09-04). The harness's default base is repo-local for an OrbStack
56
+ # inotify constraint that binds macOS dev and nothing here, so every run
57
+ # seeded the CHECKOUT with root-owned dirs a non-root `git clean -ffdx`
58
+ # cannot remove. That took commentary's checks AND integration red on
59
+ # 2026-09-03. Use the sanctioned override, per-run and outside the
60
+ # checkout -- as 8ff17a8d did in June for one debug workflow, and stopped.
61
+ base="$RUNNER_TEMP/nctt-$GITHUB_RUN_ID-$GITHUB_RUN_ATTEMPT"
62
+ mkdir -p "$base"
63
+ echo "NORSK_CTL_TEST_TMP=$base" >> "$GITHUB_ENV"
64
+ # Yesterday's bases hold dockerd-created root dirs, so a non-root rm
65
+ # EACCESes. They cannot wedge a checkout, but they do fill the disk.
66
+ for old in $(find "$RUNNER_TEMP" -maxdepth 1 -name 'nctt-*' -mtime +0 -printf '%f\n' 2>/dev/null || true); do
67
+ docker run --rm --user 0:0 -v "$RUNNER_TEMP":/t alpine sh -c 'rm -rf -- "/t/$1"' sh "$old" >/dev/null 2>&1 || true
68
+ done
69
+ # LEGACY: a runner that ran the old default still carries a workspace
70
+ # test-temp, and a checkout with clean:true dies on it. Reap the holders
71
+ # first -- rm cannot unlink a live mountpoint even as root (EBUSY), and a
72
+ # RESTARTING leaked container re-creates the path as root seconds after
73
+ # any clean. Match on mount SOURCE, not a label: the holders are untracked
74
+ # by construction, because a killed run labels nothing.
57
75
  tt="$GITHUB_WORKSPACE/test-temp"
58
76
  [ -d "$tt" ] || exit 0
59
- docker run --rm --user 0:0 -v "$tt":/t alpine sh \
60
- -c 'rm -rf /t/* /t/.[!.]* 2>/dev/null || true' || rm -rf "$tt"/* 2>/dev/null || true
77
+ stuck=""
78
+ for c in $(docker ps -aq 2>/dev/null || true); do
79
+ if docker inspect -f '{{range .Mounts}}{{println .Source}}{{end}}' "$c" 2>/dev/null | grep -q "^$tt/"; then
80
+ stuck="$stuck $c"
81
+ fi
82
+ done
83
+ if [ -n "$stuck" ]; then
84
+ echo "reaping containers holding mounts under $tt:$stuck"
85
+ docker rm -f $stuck || true
86
+ fi
87
+ # The DIRECTORY, not just its contents: an empty but root-owned base
88
+ # still EACCESes a later mkdtemp. Mounting the PARENT is what lets a root
89
+ # container unlink the leaf.
90
+ docker run --rm --user 0:0 -v "$GITHUB_WORKSPACE":/w alpine \
91
+ sh -c 'rm -rf /w/test-temp' || rm -rf "$tt" || true
92
+ # Fail HERE if it survived. The checkout fails on it either way, but
93
+ # reports only an EACCES rmdir with no clue what was holding the path.
94
+ if [ -e "$tt" ]; then
95
+ echo "::error::$tt survived the pre-checkout clean"
96
+ ls -lan "$tt" || true
97
+ exit 1
98
+ fi
61
99
 
62
100
  - uses: actions/checkout@v5
63
101
  with:
@@ -43,23 +43,61 @@ jobs:
43
43
  sync:
44
44
  runs-on: x64
45
45
  steps:
46
- # Root-owned leftovers under test-temp/ are what `clean: false` used to route
47
- # around: the integration suite bind-mounts host dirs into containers, and a
48
- # non-root git clean then EACCESes on what they wrote -- taking down whatever
49
- # innocent job checked out next. Skipping the clean cured that symptom and
50
- # caused another: every gitignored artifact survived between runs, so a test
51
- # could pass on build output an earlier job left behind and go red the first
52
- # time it landed on a cold runner (probe, 2026-09-01). Clear the leftovers
53
- # from a root container FIRST, and the checkout can clean properly again.
54
- # Best-effort by construction: no docker, no test-temp, or a failed run all
55
- # fall through without failing the job.
56
- - name: Clear stale root-owned test-temp (pre-checkout)
46
+ # Runs BEFORE checkout, and does two things: points the harness's temp base
47
+ # out of the workspace for every later step in this job, and clears whatever
48
+ # the old repo-local default left behind on this runner. The body carries the
49
+ # why. It fails the job only when legacy litter survives -- which would take
50
+ # the checkout down a step later anyway, but report nothing useful.
51
+ - name: Route test-temp out of the workspace (pre-checkout)
57
52
  run: |
58
53
  set -uo pipefail
54
+ # These runners are docker-OUTSIDE-of-docker, so a bind-mount source the
55
+ # HOST daemon has not seen before is created by dockerd, as ROOT, on the
56
+ # host -- even when the launch passes --container-user (reproduced
57
+ # 2026-09-04). The harness's default base is repo-local for an OrbStack
58
+ # inotify constraint that binds macOS dev and nothing here, so every run
59
+ # seeded the CHECKOUT with root-owned dirs a non-root `git clean -ffdx`
60
+ # cannot remove. That took commentary's checks AND integration red on
61
+ # 2026-09-03. Use the sanctioned override, per-run and outside the
62
+ # checkout -- as 8ff17a8d did in June for one debug workflow, and stopped.
63
+ base="$RUNNER_TEMP/nctt-$GITHUB_RUN_ID-$GITHUB_RUN_ATTEMPT"
64
+ mkdir -p "$base"
65
+ echo "NORSK_CTL_TEST_TMP=$base" >> "$GITHUB_ENV"
66
+ # Yesterday's bases hold dockerd-created root dirs, so a non-root rm
67
+ # EACCESes. They cannot wedge a checkout, but they do fill the disk.
68
+ for old in $(find "$RUNNER_TEMP" -maxdepth 1 -name 'nctt-*' -mtime +0 -printf '%f\n' 2>/dev/null || true); do
69
+ docker run --rm --user 0:0 -v "$RUNNER_TEMP":/t alpine sh -c 'rm -rf -- "/t/$1"' sh "$old" >/dev/null 2>&1 || true
70
+ done
71
+ # LEGACY: a runner that ran the old default still carries a workspace
72
+ # test-temp, and a checkout with clean:true dies on it. Reap the holders
73
+ # first -- rm cannot unlink a live mountpoint even as root (EBUSY), and a
74
+ # RESTARTING leaked container re-creates the path as root seconds after
75
+ # any clean. Match on mount SOURCE, not a label: the holders are untracked
76
+ # by construction, because a killed run labels nothing.
59
77
  tt="$GITHUB_WORKSPACE/test-temp"
60
78
  [ -d "$tt" ] || exit 0
61
- docker run --rm --user 0:0 -v "$tt":/t alpine sh \
62
- -c 'rm -rf /t/* /t/.[!.]* 2>/dev/null || true' || rm -rf "$tt"/* 2>/dev/null || true
79
+ stuck=""
80
+ for c in $(docker ps -aq 2>/dev/null || true); do
81
+ if docker inspect -f '{{range .Mounts}}{{println .Source}}{{end}}' "$c" 2>/dev/null | grep -q "^$tt/"; then
82
+ stuck="$stuck $c"
83
+ fi
84
+ done
85
+ if [ -n "$stuck" ]; then
86
+ echo "reaping containers holding mounts under $tt:$stuck"
87
+ docker rm -f $stuck || true
88
+ fi
89
+ # The DIRECTORY, not just its contents: an empty but root-owned base
90
+ # still EACCESes a later mkdtemp. Mounting the PARENT is what lets a root
91
+ # container unlink the leaf.
92
+ docker run --rm --user 0:0 -v "$GITHUB_WORKSPACE":/w alpine \
93
+ sh -c 'rm -rf /w/test-temp' || rm -rf "$tt" || true
94
+ # Fail HERE if it survived. The checkout fails on it either way, but
95
+ # reports only an EACCES rmdir with no clue what was holding the path.
96
+ if [ -e "$tt" ]; then
97
+ echo "::error::$tt survived the pre-checkout clean"
98
+ ls -lan "$tt" || true
99
+ exit 1
100
+ fi
63
101
 
64
102
  - uses: actions/checkout@v5
65
103
  with:
@@ -201,23 +239,61 @@ jobs:
201
239
  if: ${{ !cancelled() }}
202
240
  runs-on: x64
203
241
  steps:
204
- # Root-owned leftovers under test-temp/ are what `clean: false` used to route
205
- # around: the integration suite bind-mounts host dirs into containers, and a
206
- # non-root git clean then EACCESes on what they wrote -- taking down whatever
207
- # innocent job checked out next. Skipping the clean cured that symptom and
208
- # caused another: every gitignored artifact survived between runs, so a test
209
- # could pass on build output an earlier job left behind and go red the first
210
- # time it landed on a cold runner (probe, 2026-09-01). Clear the leftovers
211
- # from a root container FIRST, and the checkout can clean properly again.
212
- # Best-effort by construction: no docker, no test-temp, or a failed run all
213
- # fall through without failing the job.
214
- - name: Clear stale root-owned test-temp (pre-checkout)
242
+ # Runs BEFORE checkout, and does two things: points the harness's temp base
243
+ # out of the workspace for every later step in this job, and clears whatever
244
+ # the old repo-local default left behind on this runner. The body carries the
245
+ # why. It fails the job only when legacy litter survives -- which would take
246
+ # the checkout down a step later anyway, but report nothing useful.
247
+ - name: Route test-temp out of the workspace (pre-checkout)
215
248
  run: |
216
249
  set -uo pipefail
250
+ # These runners are docker-OUTSIDE-of-docker, so a bind-mount source the
251
+ # HOST daemon has not seen before is created by dockerd, as ROOT, on the
252
+ # host -- even when the launch passes --container-user (reproduced
253
+ # 2026-09-04). The harness's default base is repo-local for an OrbStack
254
+ # inotify constraint that binds macOS dev and nothing here, so every run
255
+ # seeded the CHECKOUT with root-owned dirs a non-root `git clean -ffdx`
256
+ # cannot remove. That took commentary's checks AND integration red on
257
+ # 2026-09-03. Use the sanctioned override, per-run and outside the
258
+ # checkout -- as 8ff17a8d did in June for one debug workflow, and stopped.
259
+ base="$RUNNER_TEMP/nctt-$GITHUB_RUN_ID-$GITHUB_RUN_ATTEMPT"
260
+ mkdir -p "$base"
261
+ echo "NORSK_CTL_TEST_TMP=$base" >> "$GITHUB_ENV"
262
+ # Yesterday's bases hold dockerd-created root dirs, so a non-root rm
263
+ # EACCESes. They cannot wedge a checkout, but they do fill the disk.
264
+ for old in $(find "$RUNNER_TEMP" -maxdepth 1 -name 'nctt-*' -mtime +0 -printf '%f\n' 2>/dev/null || true); do
265
+ docker run --rm --user 0:0 -v "$RUNNER_TEMP":/t alpine sh -c 'rm -rf -- "/t/$1"' sh "$old" >/dev/null 2>&1 || true
266
+ done
267
+ # LEGACY: a runner that ran the old default still carries a workspace
268
+ # test-temp, and a checkout with clean:true dies on it. Reap the holders
269
+ # first -- rm cannot unlink a live mountpoint even as root (EBUSY), and a
270
+ # RESTARTING leaked container re-creates the path as root seconds after
271
+ # any clean. Match on mount SOURCE, not a label: the holders are untracked
272
+ # by construction, because a killed run labels nothing.
217
273
  tt="$GITHUB_WORKSPACE/test-temp"
218
274
  [ -d "$tt" ] || exit 0
219
- docker run --rm --user 0:0 -v "$tt":/t alpine sh \
220
- -c 'rm -rf /t/* /t/.[!.]* 2>/dev/null || true' || rm -rf "$tt"/* 2>/dev/null || true
275
+ stuck=""
276
+ for c in $(docker ps -aq 2>/dev/null || true); do
277
+ if docker inspect -f '{{range .Mounts}}{{println .Source}}{{end}}' "$c" 2>/dev/null | grep -q "^$tt/"; then
278
+ stuck="$stuck $c"
279
+ fi
280
+ done
281
+ if [ -n "$stuck" ]; then
282
+ echo "reaping containers holding mounts under $tt:$stuck"
283
+ docker rm -f $stuck || true
284
+ fi
285
+ # The DIRECTORY, not just its contents: an empty but root-owned base
286
+ # still EACCESes a later mkdtemp. Mounting the PARENT is what lets a root
287
+ # container unlink the leaf.
288
+ docker run --rm --user 0:0 -v "$GITHUB_WORKSPACE":/w alpine \
289
+ sh -c 'rm -rf /w/test-temp' || rm -rf "$tt" || true
290
+ # Fail HERE if it survived. The checkout fails on it either way, but
291
+ # reports only an EACCES rmdir with no clue what was holding the path.
292
+ if [ -e "$tt" ]; then
293
+ echo "::error::$tt survived the pre-checkout clean"
294
+ ls -lan "$tt" || true
295
+ exit 1
296
+ fi
221
297
 
222
298
  - uses: actions/checkout@v5
223
299
  with:
@@ -25,6 +25,7 @@ import {
25
25
  type CanonicalBytes,
26
26
  CTL_HASH_LINE,
27
27
  CTL_VERSION_LINE,
28
+ carriesIntegrationMarker,
28
29
  END,
29
30
  GITIGNORE_BEGIN,
30
31
  GITIGNORE_END,
@@ -116,6 +117,33 @@ function syncSmoke(repoRoot: string, canonical: string, r: SyncReport): void {
116
117
  writeIfChanged(path, out, rel, r.written);
117
118
  }
118
119
 
120
+ // integration.yml: smoke.yml's twin, but only a copy that already carries the
121
+ // convention marker is rewritten — a hand-owned one is left untouched and named,
122
+ // because converging it is a deliberate per-repo change (hooks, a proving run),
123
+ // not something a nightly sync may do to a tier the release gate believes.
124
+ function syncIntegration(repoRoot: string, canonical: string, r: SyncReport): void {
125
+ const rel = ".github/workflows/integration.yml";
126
+ const path = join(repoRoot, rel);
127
+ if (!existsSync(path)) {
128
+ r.skipped.push(`${rel} (absent)`);
129
+ return;
130
+ }
131
+ const existing = readFileSync(path, "utf8");
132
+ if (!carriesIntegrationMarker(existing)) {
133
+ r.skipped.push(`${rel} (hand-owned: no convention marker on line 1 — converge it deliberately)`);
134
+ return;
135
+ }
136
+ const key = existing.match(/^\s*product:\s*(\S+)/m)?.[1];
137
+ if (!key || key === PRODUCT_SENTINEL) {
138
+ r.skipped.push(`${rel} (no product: key to preserve)`);
139
+ return;
140
+ }
141
+ const runnerLine = existing.match(/^\s*-?\s*runner:.*$/m)?.[0];
142
+ let out = canonical.replace(PRODUCT_LINE, `$1${key}`);
143
+ if (runnerLine !== undefined) out = out.replace(RUNNER_LINE, () => runnerLine);
144
+ writeIfChanged(path, out, rel, r.written);
145
+ }
146
+
119
147
  // flake.nix is verbatim except the dev-only ctl pin (ctlVersion + the four
120
148
  // per-platform hashes), which floats per repo. Re-emit canonical STRUCTURE with
121
149
  // the repo's pin restored in order — so a structural edit (e.g. a stray comment)
@@ -250,6 +278,7 @@ export function syncDrift(repoRoot: string, canonical: CanonicalBytes): SyncRepo
250
278
  );
251
279
  syncBuildImage(repoRoot, canonical.buildImage, r);
252
280
  syncSmoke(repoRoot, canonical.smoke, r);
281
+ syncIntegration(repoRoot, canonical.integration, r);
253
282
 
254
283
  // publish-docs.yml is optional and verbatim (no per-repo line) — only re-sync a
255
284
  // repo that already carries it, unlike biome/tsconfig which every repo must have.
@@ -294,6 +323,7 @@ if (import.meta.main) {
294
323
  gitignoreCore: readFileSync(join(dir, "gitignore.core"), "utf8"),
295
324
  buildImage: readFileSync(join(dir, "build-image.yml"), "utf8"),
296
325
  smoke: readFileSync(join(dir, "smoke.yml"), "utf8"),
326
+ integration: readFileSync(join(dir, "integration.yml"), "utf8"),
297
327
  demoShim: readFileSync(join(dir, "demo.sh"), "utf8"),
298
328
  };
299
329
  const report = syncDrift(repoRoot, canonical);
@@ -45,23 +45,61 @@ jobs:
45
45
  changed: ${{ steps.bump.outputs.changed }}
46
46
  summary: ${{ steps.bump.outputs.summary }}
47
47
  steps:
48
- # Root-owned leftovers under test-temp/ are what `clean: false` used to route
49
- # around: the integration suite bind-mounts host dirs into containers, and a
50
- # non-root git clean then EACCESes on what they wrote -- taking down whatever
51
- # innocent job checked out next. Skipping the clean cured that symptom and
52
- # caused another: every gitignored artifact survived between runs, so a test
53
- # could pass on build output an earlier job left behind and go red the first
54
- # time it landed on a cold runner (probe, 2026-09-01). Clear the leftovers
55
- # from a root container FIRST, and the checkout can clean properly again.
56
- # Best-effort by construction: no docker, no test-temp, or a failed run all
57
- # fall through without failing the job.
58
- - name: Clear stale root-owned test-temp (pre-checkout)
48
+ # Runs BEFORE checkout, and does two things: points the harness's temp base
49
+ # out of the workspace for every later step in this job, and clears whatever
50
+ # the old repo-local default left behind on this runner. The body carries the
51
+ # why. It fails the job only when legacy litter survives -- which would take
52
+ # the checkout down a step later anyway, but report nothing useful.
53
+ - name: Route test-temp out of the workspace (pre-checkout)
59
54
  run: |
60
55
  set -uo pipefail
56
+ # These runners are docker-OUTSIDE-of-docker, so a bind-mount source the
57
+ # HOST daemon has not seen before is created by dockerd, as ROOT, on the
58
+ # host -- even when the launch passes --container-user (reproduced
59
+ # 2026-09-04). The harness's default base is repo-local for an OrbStack
60
+ # inotify constraint that binds macOS dev and nothing here, so every run
61
+ # seeded the CHECKOUT with root-owned dirs a non-root `git clean -ffdx`
62
+ # cannot remove. That took commentary's checks AND integration red on
63
+ # 2026-09-03. Use the sanctioned override, per-run and outside the
64
+ # checkout -- as 8ff17a8d did in June for one debug workflow, and stopped.
65
+ base="$RUNNER_TEMP/nctt-$GITHUB_RUN_ID-$GITHUB_RUN_ATTEMPT"
66
+ mkdir -p "$base"
67
+ echo "NORSK_CTL_TEST_TMP=$base" >> "$GITHUB_ENV"
68
+ # Yesterday's bases hold dockerd-created root dirs, so a non-root rm
69
+ # EACCESes. They cannot wedge a checkout, but they do fill the disk.
70
+ for old in $(find "$RUNNER_TEMP" -maxdepth 1 -name 'nctt-*' -mtime +0 -printf '%f\n' 2>/dev/null || true); do
71
+ docker run --rm --user 0:0 -v "$RUNNER_TEMP":/t alpine sh -c 'rm -rf -- "/t/$1"' sh "$old" >/dev/null 2>&1 || true
72
+ done
73
+ # LEGACY: a runner that ran the old default still carries a workspace
74
+ # test-temp, and a checkout with clean:true dies on it. Reap the holders
75
+ # first -- rm cannot unlink a live mountpoint even as root (EBUSY), and a
76
+ # RESTARTING leaked container re-creates the path as root seconds after
77
+ # any clean. Match on mount SOURCE, not a label: the holders are untracked
78
+ # by construction, because a killed run labels nothing.
61
79
  tt="$GITHUB_WORKSPACE/test-temp"
62
80
  [ -d "$tt" ] || exit 0
63
- docker run --rm --user 0:0 -v "$tt":/t alpine sh \
64
- -c 'rm -rf /t/* /t/.[!.]* 2>/dev/null || true' || rm -rf "$tt"/* 2>/dev/null || true
81
+ stuck=""
82
+ for c in $(docker ps -aq 2>/dev/null || true); do
83
+ if docker inspect -f '{{range .Mounts}}{{println .Source}}{{end}}' "$c" 2>/dev/null | grep -q "^$tt/"; then
84
+ stuck="$stuck $c"
85
+ fi
86
+ done
87
+ if [ -n "$stuck" ]; then
88
+ echo "reaping containers holding mounts under $tt:$stuck"
89
+ docker rm -f $stuck || true
90
+ fi
91
+ # The DIRECTORY, not just its contents: an empty but root-owned base
92
+ # still EACCESes a later mkdtemp. Mounting the PARENT is what lets a root
93
+ # container unlink the leaf.
94
+ docker run --rm --user 0:0 -v "$GITHUB_WORKSPACE":/w alpine \
95
+ sh -c 'rm -rf /w/test-temp' || rm -rf "$tt" || true
96
+ # Fail HERE if it survived. The checkout fails on it either way, but
97
+ # reports only an EACCES rmdir with no clue what was holding the path.
98
+ if [ -e "$tt" ]; then
99
+ echo "::error::$tt survived the pre-checkout clean"
100
+ ls -lan "$tt" || true
101
+ exit 1
102
+ fi
65
103
 
66
104
  - uses: actions/checkout@v5
67
105
  with:
@@ -323,23 +361,61 @@ jobs:
323
361
  if: ${{ !cancelled() }}
324
362
  runs-on: x64
325
363
  steps:
326
- # Root-owned leftovers under test-temp/ are what `clean: false` used to route
327
- # around: the integration suite bind-mounts host dirs into containers, and a
328
- # non-root git clean then EACCESes on what they wrote -- taking down whatever
329
- # innocent job checked out next. Skipping the clean cured that symptom and
330
- # caused another: every gitignored artifact survived between runs, so a test
331
- # could pass on build output an earlier job left behind and go red the first
332
- # time it landed on a cold runner (probe, 2026-09-01). Clear the leftovers
333
- # from a root container FIRST, and the checkout can clean properly again.
334
- # Best-effort by construction: no docker, no test-temp, or a failed run all
335
- # fall through without failing the job.
336
- - name: Clear stale root-owned test-temp (pre-checkout)
364
+ # Runs BEFORE checkout, and does two things: points the harness's temp base
365
+ # out of the workspace for every later step in this job, and clears whatever
366
+ # the old repo-local default left behind on this runner. The body carries the
367
+ # why. It fails the job only when legacy litter survives -- which would take
368
+ # the checkout down a step later anyway, but report nothing useful.
369
+ - name: Route test-temp out of the workspace (pre-checkout)
337
370
  run: |
338
371
  set -uo pipefail
372
+ # These runners are docker-OUTSIDE-of-docker, so a bind-mount source the
373
+ # HOST daemon has not seen before is created by dockerd, as ROOT, on the
374
+ # host -- even when the launch passes --container-user (reproduced
375
+ # 2026-09-04). The harness's default base is repo-local for an OrbStack
376
+ # inotify constraint that binds macOS dev and nothing here, so every run
377
+ # seeded the CHECKOUT with root-owned dirs a non-root `git clean -ffdx`
378
+ # cannot remove. That took commentary's checks AND integration red on
379
+ # 2026-09-03. Use the sanctioned override, per-run and outside the
380
+ # checkout -- as 8ff17a8d did in June for one debug workflow, and stopped.
381
+ base="$RUNNER_TEMP/nctt-$GITHUB_RUN_ID-$GITHUB_RUN_ATTEMPT"
382
+ mkdir -p "$base"
383
+ echo "NORSK_CTL_TEST_TMP=$base" >> "$GITHUB_ENV"
384
+ # Yesterday's bases hold dockerd-created root dirs, so a non-root rm
385
+ # EACCESes. They cannot wedge a checkout, but they do fill the disk.
386
+ for old in $(find "$RUNNER_TEMP" -maxdepth 1 -name 'nctt-*' -mtime +0 -printf '%f\n' 2>/dev/null || true); do
387
+ docker run --rm --user 0:0 -v "$RUNNER_TEMP":/t alpine sh -c 'rm -rf -- "/t/$1"' sh "$old" >/dev/null 2>&1 || true
388
+ done
389
+ # LEGACY: a runner that ran the old default still carries a workspace
390
+ # test-temp, and a checkout with clean:true dies on it. Reap the holders
391
+ # first -- rm cannot unlink a live mountpoint even as root (EBUSY), and a
392
+ # RESTARTING leaked container re-creates the path as root seconds after
393
+ # any clean. Match on mount SOURCE, not a label: the holders are untracked
394
+ # by construction, because a killed run labels nothing.
339
395
  tt="$GITHUB_WORKSPACE/test-temp"
340
396
  [ -d "$tt" ] || exit 0
341
- docker run --rm --user 0:0 -v "$tt":/t alpine sh \
342
- -c 'rm -rf /t/* /t/.[!.]* 2>/dev/null || true' || rm -rf "$tt"/* 2>/dev/null || true
397
+ stuck=""
398
+ for c in $(docker ps -aq 2>/dev/null || true); do
399
+ if docker inspect -f '{{range .Mounts}}{{println .Source}}{{end}}' "$c" 2>/dev/null | grep -q "^$tt/"; then
400
+ stuck="$stuck $c"
401
+ fi
402
+ done
403
+ if [ -n "$stuck" ]; then
404
+ echo "reaping containers holding mounts under $tt:$stuck"
405
+ docker rm -f $stuck || true
406
+ fi
407
+ # The DIRECTORY, not just its contents: an empty but root-owned base
408
+ # still EACCESes a later mkdtemp. Mounting the PARENT is what lets a root
409
+ # container unlink the leaf.
410
+ docker run --rm --user 0:0 -v "$GITHUB_WORKSPACE":/w alpine \
411
+ sh -c 'rm -rf /w/test-temp' || rm -rf "$tt" || true
412
+ # Fail HERE if it survived. The checkout fails on it either way, but
413
+ # reports only an EACCES rmdir with no clue what was holding the path.
414
+ if [ -e "$tt" ]; then
415
+ echo "::error::$tt survived the pre-checkout clean"
416
+ ls -lan "$tt" || true
417
+ exit 1
418
+ fi
343
419
 
344
420
  - uses: actions/checkout@v5
345
421
  with: