@norskvideo/ctl-dev-kit 0.2.92 → 0.2.94

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.
@@ -176,12 +176,14 @@ ln -s ../../../../../docs/generated/<slug> website/src/content/docs/guides/<slug
176
176
  ```
177
177
 
178
178
  `docs:site` runs the dev-kit's `docs/guide-stubs.ts stub` first, so the site
179
- builds on a checkout that has never captured; `publish-docs-site.yml` runs
180
- `guide-stubs.ts check` after the build and refuses to deploy while any guide
181
- is still a placeholder. That refusal is deliberate: a product that declares
182
- recorded guides must also restore (or regenerate) its captures in that
183
- workflow before the build, and until it does, the publish stops rather than
184
- shipping an empty page.
179
+ builds on a checkout that has never captured. The captures come from the
180
+ product's nightly `publish-docs.yml`, which keeps `docs/generated` as the
181
+ `docs-captures` artifact after a passing engine tier; `publish-docs-site.yml`
182
+ downloads the newest one before its build (and runs when `publish-docs` completes, so a
183
+ fresh capture publishes without waiting for a push). It then runs
184
+ `guide-stubs.ts check` and refuses to deploy while any guide is still a
185
+ placeholder: until the guide has been captured once, the publish stops rather
186
+ than shipping an empty page.
185
187
 
186
188
  ## The two builds
187
189
 
@@ -211,9 +213,12 @@ holds the copy byte-identical, and `bun run sync:drift` writes it — creating i
211
213
  where the repo has a site and is not a turnkey. On every push to `main` (and on
212
214
  demand) it installs `website/`, builds the public variant and deploys
213
215
  `website/dist-public` to Cloudflare Pages with `wrangler`. It never cancels a
214
- run in flight, because a cancelled deploy is a half-published site. It restores
215
- no capture cache: a product site builds from the committed prose, so there is
216
- nothing a nightly run would have that a push does not.
216
+ run in flight, because a cancelled deploy is a half-published site. Before the
217
+ build it downloads the newest recorded-guide captures (the `docs-captures`
218
+ artifact `publish-docs.yml` keeps for 30 days, not the Actions cache, whose
219
+ entries are versioned by a compression that varies across runners); a site
220
+ with no recorded guides restores nothing it reads, and builds from its
221
+ committed prose.
217
222
 
218
223
  Where it may exist is the gate's business (ADR-0012, and the documentation
219
224
  plan): a repo with `website/astro.config.mjs` may carry it; a repo without a
@@ -4,12 +4,14 @@
4
4
  #
5
5
  # This is the SITE channel, not the bundle: publish-docs.yml / build-docs.yml
6
6
  # regenerate the illustrated manual the product image serves at /docs, nightly,
7
- # from a licensed Docker run. The site builds from the committed prose alone,
8
- # needs no licence and no Docker, and so rides every push (conventions/
9
- # docs-site.md, "Two documentation channels"). A site that also symlinks
10
- # RECORDED guides (website/src/content/docs/guides/<slug> -> docs/generated/<slug>)
11
- # builds against a placeholder when the capture is absent, and the gate below
12
- # refuses to deploy one.
7
+ # from a licensed Docker run. The site needs no licence and no Docker, and so
8
+ # rides every push (conventions/docs-site.md, "Two documentation channels").
9
+ # A site that also symlinks RECORDED guides (website/src/content/docs/guides/
10
+ # <slug> -> docs/generated/<slug>) publishes them from the captures that nightly
11
+ # run keeps as an artifact: they are restored before the build, which
12
+ # stubs only a guide never captured, and the gate below refuses to deploy a
13
+ # stub. So the site also runs when publish-docs completes, to publish a fresh
14
+ # capture without waiting for the next push.
13
15
  #
14
16
  # This workflow is SINGLE-SOURCED in @norskvideo/ctl-dev-kit
15
17
  # (conventions/publish-docs-site.yml) and copied verbatim: there is no per-repo
@@ -40,9 +42,15 @@ on:
40
42
  push:
41
43
  branches: [main]
42
44
  workflow_dispatch:
45
+ # a fresh capture of the recorded guides (publish-docs.yml saves it)
46
+ workflow_run:
47
+ workflows: [publish-docs]
48
+ types: [completed]
49
+ branches: [main]
43
50
 
44
51
  permissions:
45
52
  contents: read
53
+ actions: read # the newest docs-captures artifact, from the capture run
46
54
 
47
55
  # Never cancel in flight: a cancelled `wrangler pages deploy` is a half-published
48
56
  # site, and the next push rebuilds from the same inputs anyway. Queue instead.
@@ -114,6 +122,30 @@ jobs:
114
122
  with:
115
123
  clean: true
116
124
 
125
+ # The recorded guides' captures, from the product's nightly capture run
126
+ # (publish-docs.yml keeps docs/generated as the docs-captures artifact
127
+ # after a passing engine tier): the newest unexpired one, put where
128
+ # docs:site:public expects it. None yet -- a site that records no guides,
129
+ # or before the first capture -- restores nothing; the build stubs what is
130
+ # missing and the gate below refuses to deploy a stub. gh comes from the
131
+ # build shell (the runners have no system gh).
132
+ - name: Restore the recorded guides' captures
133
+ env:
134
+ GH_TOKEN: ${{ github.token }}
135
+ run: |
136
+ nix develop .#build --command bash -c '
137
+ set -euo pipefail
138
+ run="$(gh api "repos/$GITHUB_REPOSITORY/actions/artifacts?name=docs-captures&per_page=20" \
139
+ --jq "[.artifacts[] | select(.expired | not)][0].workflow_run.id // empty")"
140
+ if [ -z "$run" ]; then
141
+ echo "no docs-captures artifact yet: nothing to restore"
142
+ exit 0
143
+ fi
144
+ mkdir -p docs/generated
145
+ gh run download "$run" --repo "$GITHUB_REPOSITORY" --name docs-captures --dir docs/generated
146
+ echo "restored the recorded guides captured by run $run"
147
+ '
148
+
117
149
  # website/ is a STANDALONE package -- its own bun.lock, outside the root
118
150
  # workspaces -- so the repo-root install never covers it, and the build
119
151
  # needs both: the root for @norskvideo/ctl-dev-kit (docs:site:public stubs
@@ -145,8 +177,9 @@ jobs:
145
177
  # be replaced with "run the doc-guide locally", and nothing else would
146
178
  # notice -- the build is green, the links resolve. --content reads the
147
179
  # guides the site declares by symlink, so a site that declares none has
148
- # nothing to refuse; one that does needs its captures on the runner, and
149
- # until the repo restores them this step says which pages are missing.
180
+ # nothing to refuse; one that does needs its captures, restored above,
181
+ # and until the nightly run has captured them this step says which pages
182
+ # are missing.
150
183
  - name: Refuse to publish placeholder guides
151
184
  run: |
152
185
  nix develop .#build --command bash -c '
@@ -318,6 +318,23 @@ jobs:
318
318
  if: ${{ steps.engine.outcome == 'success' }}
319
319
  run: nix develop .#build --command bun run docs:manual
320
320
 
321
+ # The captures, for the product's own docs site: publish-docs-site.yml
322
+ # downloads the newest docs-captures artifact, so its recorded guides
323
+ # publish from this run, the only one that can make them. Only after a
324
+ # passing engine tier, so a site never takes a half-captured set over the
325
+ # last good one. An artifact, not actions/cache: a cache entry is
326
+ # versioned by its compression, and the runner pool mixes machines with
327
+ # and without zstd, so a save on one never matched a restore on another
328
+ # (relay, 2026-10-21: saved on ashton-nuc, missed on test2-runner-1).
329
+ - name: Keep the guide captures for the docs site
330
+ if: ${{ steps.engine.outcome == 'success' }}
331
+ uses: actions/upload-artifact@v4
332
+ with:
333
+ name: docs-captures
334
+ path: docs/generated
335
+ retention-days: 30
336
+ if-no-files-found: error
337
+
321
338
  # Said three ways, so a failure is never silent: a warning on the run, a
322
339
  # line in its summary, and the cell's detail (the notify job).
323
340
  - name: Report the engine tier (not gating)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@norskvideo/ctl-dev-kit",
3
- "version": "0.2.92",
3
+ "version": "0.2.94",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  "./create-product": "./create-product/create-product.ts",