Repository navigation
Description
Part of #554, change set B (Actions cache hygiene). Work on main. Rulings: #554 rulings 1, 4, 5, 6, 15, 16.
Summary
- Today.
.github/actions/setup-bunand.github/actions/setup-cypressuseactions/cache. Its post step saves at the end of every job, on every event, pull requests included. Saves race, fail and cost seconds on the gate path. The🔒 Security Auditjob saves an--ignore-scriptstree under the shared key. - After. Both actions restore with
actions/cache/restoreand save withactions/cache/saveonly on a primary-key miss, never onpull_request. Bun is pinned to1.4.4in CI. - Measured saving. Post steps fell from 5–21 s per job to 0–2 s in R1, and to 0–1 s after it. The gate-path effect is not isolated; Measure CI/CD time to live after the v2.3 work: 1090 s median before #569 owns M2g. This change is mostly about reliability.
Benchmark
| Field | Value |
|---|---|
| Metric | active_caches_size_in_bytes from gh api repos/docs-plus/docs.plus/actions/cache/usage, in bytes, with the entry count |
| Before | 10,480,109,180 B in 87 entries (2026-10-20). 10 Linux-bun / Linux-cypress entries on refs/pull/* |
| After | 3,298,092,956 B in 76 entries, read 2026-11-11 16:21Z. 0 entries of any kind on refs/pull/*. By prefix: Linux-bun-v2-1.4.4 3,000,370,312 B in 6; Linux-cypress-16.2.1 225,703,061 B in 1; the oven-sh/setup-bun binary 50,544,726 B in 1; ext-v3 21,474,857 B in 68 |
| Condition | GitHub-hosted ubuntu-latest. prod.docs.plus.yml, chatroom-e2e.yml and editor-e2e.yml on main. Exact counts from the GitHub API and job logs |
| How to run | gh api repos/docs-plus/docs.plus/actions/cache/usage, then the entry list in Verification |
| Pass rule | Under 5,000,000,000 B 7 days after the merge, and 0 new Linux-bun / Linux-cypress entries on refs/pull/*. Met on 2026-11-11 |
| Guard | 0 Unable to reserve cache on an unchanged-lock run (R2, run 41677887088). Every hosted setup-bun job runs the one pinned Bun |
| Owner | Agent in the repo: the close read. Maintainer: the close |
| Claim | "The CI cache shrank from 10.5 GB to 3.3 GB, 69 % smaller, and pull requests no longer write to it." (internal) |
Supporting reads:
| Read | Before | After |
|---|---|---|
Unable to reserve cache (Linux-bun or Linux-cypress), unchanged bun.lock |
not measured before | 0 (run 41677887088) |
The same, bun.lock changed |
10 (run 39398067267) | 10 and 8 (runs 41626334830, 41636667896); they fail no job; accepted, #554 ruling 16 |
| Setup post-step seconds per gate job | 5–21 s (run 39398067267) | 0–1 s on the 2026-11-03 runs (Security Audit 2 s once, in R1). 0–1 s on every setup post step of the 13 push runs on main, 2026-11-07 to 2026-11-11 (read 2026-11-11) |
| Bun versions across hosted jobs | 2 (1.4.3 latest, 1.4.1 chatroom) |
1 (1.4.4 pin, 72f08af7a) |
M6 on Dependabot PR runs that changed bun.lock (record, not a gate) |
median 496 s, range 461–579 s, n = 5 successful runs (2026-10-19 to 2026-10-23) | median 515 s, range 386–603 s, n = 3 successful runs (2026-11-03) |
Depends on / Blocks
- Depends on: nothing.
- Blocks: nothing.
- Related. Measure CI/CD time to live after the v2.3 work: 1090 s median before #569 owns the final time-to-live result. Write a timing table to every CI/CD run summary #556's timing table also shows these post steps.
Current behaviour
Links are pinned to d0a53756f8676556358b6adc6c2397d2ed7c64c8.
setup-bundefaults tolatest(setup-bun/action.yml:11-20).bun-versionhasdefault: 'latest'. No caller passescache-version, so every key usesv1. In run 39398067267 every gate job loggedDownloading a new version of Bun: https://github.com/oven-sh/bun/releases/download/bun-v1.4.3/bun-linux-x64.zip.
setup-buncaches withactions/cache, which saves in a post step (setup-bun/action.yml:36-54).- The key is
${{ runner.os }}-bun-${{ inputs.cache-version }}-${{ steps.setup-bun.outputs.bun-version }}-${{ hashFiles('**/bun.lock') }}. - Lines 46-50 keep the version in the key for two reasons: the
latestdefault, which the pin ends, and native addons, which stay. - The repo has one lockfile, the root
bun.lock(dependabot.yml:19-23).
- The key is
- The security job saves an
--ignore-scriptstree under the shared key.prod.docs.plus.yml:230-233passesignore-scripts: 'true'. The key does not encode that input.- In job 118545695054,
bun install --frozen-lockfile --ignore-scriptsran at 09:05:37. The post step loggedCache saved with key: Linux-bun-v1-1.4.3-6e2b83abc8e667f5f7ced75c74f6e0269d7a685e5e5ba25f0684f29179390e59at 09:05:57. - The 6 Ext jobs,
🧪 Webapp Unit Testsand🏗️ Build Verificationthen hit that key. Lines 46-50 state that--frozen-lockfile"relinks rather than rebuilds" native addons, so those jobs ran on a tree where lifecycle scripts never ran.
setup-cypresskeys the binary onbun.lockand restores by prefix (setup-cypress/action.yml:24-31).key: ${{ runner.os }}-cypress-${{ hashFiles('**/bun.lock') }}andrestore-keys: ${{ runner.os }}-cypress-.- Every
bun.lockchange makes a new key, even when Cypress stays the same. In run 39398067267 every Ext job missedLinux-cypress-6e2b83ab…, restoredLinux-cypress-85af30df…by prefix, and foundCypress 15.21.1 is installed. **/bun.lockwalks the restorednode_modules: 5.5–9.8 s per Ext job, against 0.25–0.40 s for the Bun key.- The install runs from
extensions/extension-hyperlinkon purpose (setup-cypress/action.yml:8-15,:33-43).
- A prefix restore stores two binaries in one entry. In PR 540 (
bump cypress from 15.21.1 to 16.2.0), run 39275480131, job 118139333483 restored the 15.21.1 entry (457591034bytes) by prefix. It then loggedInstalling Cypress (version: 16.2.0). The entry saved onrefs/pull/540/mergeis683165434bytes, so it holds both binaries. - Every Ext job failed to save Cypress, and 4 gate jobs failed to save Bun.
- Chatroom run 39398067266 on the same push saved
Linux-cypress-6e2b83ab…at 09:08:32. - All 6 Ext jobs in deploy run 39398067267 reached their post step after 09:08:45. Each logged
Failed to save: Unable to reserve cache with key Linux-cypress-6e2b83ab…, another job may be creating this cache.Jobs: 118546569637, 118546569663, 118546569702, 118546569703, 118546569709, 118546569810. - The Bun key failed the same way in
📝 Type Check(118545694917),🧪 Backend Tests(118545695206),🧪 Backend E2E(118545695380) and🔍 Lint & Format(118545695209).
- Chatroom run 39398067266 on the same push saved
- Post-step seconds in run 39398067267, from
gh run view 39398067267 --json jobs.🏗️ Build Verificationwaits for every Ext job, so the Ext post steps sit on the gate path.setup-cypresspost: 10–15 s on each of the 6🧪 Ext (…)jobs.setup-bunpost: 6–10 s on Ext jobs;🧪 Backend Tests21 s,🔒 Security Audit18 s,📝 Type Check14 s,🔍 Lint & Format14 s,🧪 Backend E2E11 s,🧪 Webapp Unit Tests8 s,🏗️ Build Verification5 s.- On an exact hit the Bun post step only logs
not saving cache. It still took 7.9 s in job 118546569637, of whichoven-sh/setup-buntook 179 ms.
- The cache on 2026-10-20.
gh api repos/docs-plus/docs.plus/actions/cache/usagereturned10480109180bytes in87entries.65sit on Dependabot PR refs (refs/pull/534/mergetorefs/pull/540/merge). By key prefix, fromgh api repos/docs-plus/docs.plus/actions/caches:Linux-bun: 4 entries onmain(3.56 GB), 5 onrefs/pull/*(3.43 GB).mainholdsLinux-bun-v1-1.4.3-…(683305960bytes) andLinux-bun-v1-1.4.1-…(1099659056bytes) per lock hash. The 1.4.1 entries come fromchatroom-e2e.yml, whose post step saves after the suite.Linux-cypress: 2 onmain(0.92 GB), 5 onrefs/pull/*(2.51 GB).ext-v3(from.github/actions/build-extensions): 55 onrefs/pull/*(0.01 GB), 15 onmain(under 0.01 GB).bun-+CxZWfwTi+/AufZaQ1DSt6rSdDY=(fromoven-sh/setup-bun): 1 onmain(0.04 GB).
- Two workflows already pin Bun
1.4.1.chatroom-e2e.yml:54-57passesbun-version: '1.4.1'tosetup-bun.lockstep-guard.yml:32-35callsoven-sh/setup-bundirectly withbun-version: '1.4.1'.- Chatroom run 39398067266 logged
bun install v1.4.1 (4661e494f)on the currentbun.lockwith--frozen-lockfile, and succeeded. - The prod image build in deploy job 118549257854 logged
bun install v1.4.3 (c6da4a4d3)7 times. bun-typesis^1.4.2(package.json:105), locked atbun-types@1.4.2.
- The callers.
setup-bunis used atprod.docs.plus.yml:206,:231,:293,:327and:385;backend-ci.yml:26and:85;quality-lint.yml:21;chatroom-e2e.yml:54; andstage.docs.plus.yml:68,:86(withignore-scripts: 'true'at:88),:116,:142and:168.- Added after the pinned commit:
editor-e2e.yml(setup-bunandsetup-cypress, added incfb5bc8e4) andsupabase-policies.yml(setup-bun). setup-cypressis used atprod.docs.plus.yml:297,chatroom-e2e.yml:57andstage.docs.plus.yml:122. Each caller runssetup-bunfirst.- No caller reads
setup-bun'scache-hitoutput. 🏗️ Build Verificationlistsextension-testsinneeds(prod.docs.plus.yml:355-365).extensions.yaml:13-15lists both actions as shared inputs, so a push that edits them runs every Ext suite.
- Added after the pinned commit:
- The pinned
actions/cacheSHA has both sub-actions. Tagv6.1.0is commit55cc8345863c7cc4c66a329aec7e433d2d1c52a9.restore/action.ymlhas thelookup-onlyinput and thecache-hitandcache-primary-keyoutputs.save/action.ymltakespathandkey. Neither sub-action has a post step.- All third-party actions are pinned to a commit SHA (
prod.docs.plus.yml:25-26).
Target behaviour
- No cache post step in either action. The
Post Run ./.github/actions/setup-bunstep keeps only theoven-sh/setup-bunpart, about 0.2 s. - Pull request runs restore and never save a
Linux-bun-…orLinux-cypress-…entry. - Other events (
push,schedule,workflow_dispatch) save only when three things hold. The restore missed the primary key. A lookup finds no entry for that key yet. For Bun, the install ran without--ignore-scripts. - The Bun save runs right after the install, so the entry holds only install output.
- Bun key:
Linux-bun-v2-<Bun version>-<hashFiles('bun.lock')>, with the same prefix restore.v2drops every old entry, including the--ignore-scriptstree. - Cypress key:
Linux-cypress-<installed Cypress version>, for exampleLinux-cypress-15.21.1, with norestore-keys. - Bun version. Every
setup-bunjob andlockstep-guard.ymlrun1.4.4.chatroom-e2e.ymlhas no override. - Cache usage stays under
5000000000bytes 7 days after the merge. This is computed: one Bun entry of683305960to1099659056bytes per lock hash used in 7 days, plus one457591034-byte Cypress entry.
Implementation steps
Read Read first before Step 0. "Comment here" means a comment on this GitHub issue, never a code comment. Line numbers refer to the pinned commit. Find each edit by its quoted text.
Step 0. Read and check the base
-
Confirm a clean base, then compare the cited files with the pinned commit.
git status --short .github git fetch origin main git diff --stat d0a53756f8676556358b6adc6c2397d2ed7c64c8 origin/main -- \ .github/actions/setup-bun .github/actions/setup-cypress \ .github/workflows/chatroom-e2e.yml .github/workflows/lockstep-guard.yml \ .github/filters/extensions.yaml .github/WORKFLOWS.md
- Stop and comment here if
git statusshows edits under.github/actions. - If either
action.ymldiffers from the pinned commit, stop, re-derive Steps 1 and 2 from the new file, and comment here. - If another listed file differs, continue. Make CI failures reach Telegram: set the watchdog secrets, alert on red E2E pushes #557 (set A) edits
chatroom-e2e.ymland.github/WORKFLOWS.md.
- Stop and comment here if
-
List the callers again. Set B siblings also edit
prod.docs.plus.yml.git grep -n -E 'setup-bun|setup-cypress|ignore-scripts|bun-version|cache-version|outputs\.cache-hit' origin/main -- .github- Expect the callers in Current behaviour item 10.
- Stop and comment here if a caller passes
cache-version, or readssetup-bun'scache-hitoutput, or callssetup-cypressbeforesetup-bun.
-
Confirm the
actions/cachepin.gh api repos/actions/cache/git/refs/tags/v6.1.0 --jq .object.sha gh api "repos/actions/cache/contents/restore/action.yml?ref=55cc8345863c7cc4c66a329aec7e433d2d1c52a9" --jq .content | base64 -d | grep -nE 'lookup-only|cache-primary-key|cache-hit' git grep -n 'actions/cache@' origin/main -- .github
- Expect
55cc8345863c7cc4c66a329aec7e433d2d1c52a9. If Dependabot bumpedactions/cacheonmain, use the SHA inbuild-extensions/action.ymland repeat therestore/action.ymlcheck on it.
- Expect
-
Record the
actionlintbaseline.actionlint -config-file .github/actionlint.yaml
- At the pinned commit it exits 1 with 4 findings: two
SC2016indiscord-release.yml:156, oneSC2016inlockstep-guard.yml:38, and the unknownstage.docs.pluslabel instage.docs.plus.yml:194. Write down your list for Step 6.
- At the pinned commit it exits 1 with 4 findings: two
Step 1. .github/actions/setup-cypress/action.yml
Keep lines 1-16 (the header) as they are. Replace lines 18-43 with the block below.
name: 'Setup Cypress Binary'
description: 'Cache and install the Cypress test runner binary'
runs:
using: 'composite'
steps:
# Keyed on the installed version, not bun.lock: most lock changes keep the
# same binary. Needs setup-bun first, so node_modules holds the pinned cypress.
- name: 🏷️ Read Cypress version
id: version
shell: bash
working-directory: extensions/extension-hyperlink
run: |
version=$(bun -e "console.log(require('cypress/package.json').version)")
[ -n "$version" ] || { echo "::error::cypress is not installed; run setup-bun first"; exit 1; }
echo "version=$version" >> "$GITHUB_OUTPUT"
# No restore-keys: a prefix hit restores the old binary, and the save then
# stores both versions in one entry.
- name: 📦 Restore Cypress binary
id: cypress-cache
uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: ~/.cache/Cypress
key: ${{ runner.os }}-cypress-${{ steps.version.outputs.version }}
- name: 🌲 Install Cypress binary
shell: bash
working-directory: extensions/extension-hyperlink
run: |
if [ "${{ steps.cypress-cache.outputs.cache-hit }}" = "true" ]; then
echo "✅ Cypress cache HIT"
else
echo "📦 Downloading Cypress binary…"
fi
bunx cypress install
bunx cypress verify
# Pull requests read main's entries and never save. The lookup skips a key
# that another job already saved.
- name: 🔎 Look up saved Cypress binary
id: lookup
if: github.event_name != 'pull_request' && steps.cypress-cache.outputs.cache-hit != 'true'
uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: ~/.cache/Cypress
key: ${{ steps.cypress-cache.outputs.cache-primary-key }}
lookup-only: true
- name: 💾 Save Cypress binary
if: steps.lookup.outcome == 'success' && steps.lookup.outputs.cache-hit != 'true'
uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: ~/.cache/Cypress
key: ${{ steps.cypress-cache.outputs.cache-primary-key }}Check it:
(cd extensions/extension-hyperlink && bun -e "console.log(require('cypress/package.json').version)")Expect 15.21.1 at the pinned commit, or the version in the root package.json cypress entry on main.
Step 2. .github/actions/setup-bun/action.yml: restore, install, then save
Change line 20 from default: 'v1' to default: 'v2'. Keep the other lines up to 35. Replace lines 36-60 with the block below.
- name: 📦 Restore Dependencies
id: cache
uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
# Keep the three path lists in this file equal: the cache version hashes them.
path: |
~/.bun/install/cache
node_modules
packages/*/node_modules
apps/*/node_modules
extensions/*/node_modules
# The Bun version stays in the key: cached node_modules hold native addons
# built for one Bun, and --frozen-lockfile relinks them without a rebuild.
key: ${{ runner.os }}-bun-${{ inputs.cache-version }}-${{
steps.setup-bun.outputs.bun-version }}-${{ hashFiles('bun.lock') }}
restore-keys: |
${{ runner.os }}-bun-${{ inputs.cache-version }}-${{ steps.setup-bun.outputs.bun-version }}-
- name: 📥 Install Dependencies
shell: bash
run: |
[ "${{ steps.cache.outputs.cache-hit }}" = "true" ] && echo "✅ Cache HIT" || echo "📦 Installing..."
bun install --frozen-lockfile ${{ inputs.ignore-scripts == 'true' && '--ignore-scripts' || '' }}
# Pull requests read main's entries and never save. An --ignore-scripts tree
# must not become the shared entry. The lookup skips a key another job saved.
- name: 🔎 Look up saved dependencies
id: lookup
if: github.event_name != 'pull_request' && steps.cache.outputs.cache-hit != 'true' && inputs.ignore-scripts != 'true'
uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: |
~/.bun/install/cache
node_modules
packages/*/node_modules
apps/*/node_modules
extensions/*/node_modules
key: ${{ steps.cache.outputs.cache-primary-key }}
lookup-only: true
- name: 💾 Save Dependencies
if: steps.lookup.outcome == 'success' && steps.lookup.outputs.cache-hit != 'true'
uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: |
~/.bun/install/cache
node_modules
packages/*/node_modules
apps/*/node_modules
extensions/*/node_modules
key: ${{ steps.cache.outputs.cache-primary-key }}- Keep
id: cache. Thecache-hitoutput at lines 22-25 readssteps.cache.outputs.cache-hit, andactions/cache/restoresets it too. - In the header, after line 5, add:
# Pull requests restore only. Other events save once per key, after the install. - Why
v2: without it, new runs get exact hits on the old1099659056-byte chatroom entry, so the save path never runs. The first run pays one coldbun installper job.
Check it:
bun -e "const y = Bun.YAML.parse(await Bun.file('.github/actions/setup-bun/action.yml').text()); console.log(y.runs.steps.map((s) => s.name).join(' | '))"Expect 🥟 Setup Bun | 📦 Restore Dependencies | 📥 Install Dependencies | 🔎 Look up saved dependencies | 💾 Save Dependencies.
Step 3. Pin Bun at 1.4.4
Shipped at 1.4.1 in e3b4a213a. #650 moved it to 1.4.4 in 72f08af7a (2026-11-03), and the 2026-11-06 ruling amended this body to match. Today the block and the check read 1.4.4.
-
In
.github/actions/setup-bun/action.yml, replace the threebun-version:input lines (bun-version:,description: 'Bun version',default: 'latest') with the block below. They are lines 12-14 at the pinned commit and lines 13-15 after Step 2.bun-version: description: 'Bun version. Pinned on purpose; bump by hand, never below the 1.4.0 floor (AGENTS.md).' default: '1.4.4'
-
.github/workflows/lockstep-guard.yml:35readsbun-version: '1.4.4'. Make no change there. -
Do not edit any Dockerfile. The images stay on
oven/bun:1-slim.
Check it:
git grep -n -E "bun-version|oven/bun:" -- .github apps/*/dockerExpect default: '1.4.4' in setup-bun/action.yml, '1.4.4' in lockstep-guard.yml, latest only in stage.docs.plus.yml:219, and only oven/bun:1-slim in the Dockerfiles.
Step 4. .github/workflows/chatroom-e2e.yml
Under - uses: ./.github/actions/setup-bun, delete the with: and bun-version: '1.4.1' lines (55-56). The suite then runs the setup-bun pin.
Check it:
actionlint -config-file .github/actionlint.yaml .github/workflows/chatroom-e2e.ymlExpect no output.
Step 5. .github/WORKFLOWS.md
In §Related files, replace the line - Composite action: `actions/setup-bun/action.yml` (line 96 at the pinned commit) with these lines.
- Composite actions: `actions/setup-bun/action.yml`, `actions/setup-cypress/action.yml`, `actions/build-extensions/action.yml`
- Cache rule for `setup-bun` and `setup-cypress`: pull requests restore only. Other events save once per key. The `--ignore-scripts` install never saves.
- `setup-bun` pins the Bun version for CI. Bump it by hand. The Docker images stay on `oven/bun:1-slim`.Step 6. Local checks
actionlint -config-file .github/actionlint.yaml
bun -e "for (const f of ['.github/actions/setup-bun/action.yml','.github/actions/setup-cypress/action.yml']) { const y = Bun.YAML.parse(await Bun.file(f).text()); console.log(f, y.runs.steps.length, 'steps') }"
grep -n 'uses: ' .github/actions/setup-bun/action.yml .github/actions/setup-cypress/action.yml
grep -rn 'actions/cache@' .github/actions/setup-bun .github/actions/setup-cypress || echo "no actions/cache@ left"
bunx prettier --check .github/actions/setup-bun/action.yml .github/actions/setup-cypress/action.yml .github/workflows/chatroom-e2e.yml .github/WORKFLOWS.mdactionlintshows the Step 0.4 findings and nothing new. It does not read compositeaction.ymlfiles, so the YAML line checks them:5 stepsfor each.- Every
uses:line ends in a 40-character SHA and a# v…comment. - If prettier fails, rerun it with
--write, then read the diff again.
Review checkpoint
git status --short
git diff --stat
git diff -- .github/actions/setup-bun/action.yml .github/actions/setup-cypress/action.yml .github/workflows/chatroom-e2e.yml .github/WORKFLOWS.md- Expect changes in those 4 files only. Show the diff to the maintainer.
- Commit and push per SP2 ([Tracking] Faster, change-aware CI/CD pipeline #554), as its own commit, with a subject that does not start with
(build):. No deploy is needed. Both actions are_sharedinputs in.github/filters/extensions.yaml, so that push runs every Ext suite.
Acceptance criteria
-
setup-bunandsetup-cypresscontain noactions/cache@line. Each usesactions/cache/restoreandactions/cache/save, pinned by full SHA. - The Bun key uses
hashFiles('bun.lock'). The Cypress key is${{ runner.os }}-cypress-<version>and has norestore-keys. - The save steps are skipped on
pull_request, on an exact hit, after a lookup hit, and forignore-scripts: 'true'. -
cache-versiondefaults tov2. In R1,🔒 Security Auditsaves nothing. In R1 or its chatroom run, one job saves aLinux-bun-v2-…entry. -
setup-bundefaults to1.4.4, andlockstep-guard.ymlreads1.4.4. -
chatroom-e2e.ymlpasses nobun-versiontosetup-bun. - No Dockerfile changed. The images stay on
oven/bun:1-slim. -
actionlintshows no new findings beyond the Step 0.4 baseline. -
.github/WORKFLOWS.mdstates the cache rule and the pin. - Run R1 and run R2 (see Verification) are green, and the SP3 comment exists.
- In R2, no job logs
Unable to reserve cache with key Linux-bunorUnable to reserve cache with key Linux-cypress. - In R1, every job that runs
setup-bunlogsbun install v1.4.4.🚀 Deploy Productionis excluded, because its image build usesoven/bun:1-slim. - No cache entry on a
refs/pull/*ref has a key that starts withLinux-bun-v2-or matches^Linux-cypress-[0-9]+\.[0-9]+\.[0-9]+$.
Verification
Before the push. Run Step 6. bash .github/scripts/parse-build-trigger.test.sh and a dry_run_subject dispatch are not needed, because triage and gating do not change.
After the push. Measure from normal runs only. The save path needs a non-PR run on main.
- R1 is the first
prod.docs.plus.ymlpush run onmainwith this change in which the🧪 Extjobs ran, plus thechatroom-e2e.ymlrun of that push. R1 pays cold installs, so use it for correctness only.- One job logs
Cache saved with key: Linux-cypress-. - A job that reaches
🔎 Look up saved dependenciesafter the Bun save shows💾 Save Dependenciesas skipped.
- One job logs
- R2 is the next push run on
mainwhere at least one Ext suite ran andbun.lockdid not change.
Post-step seconds per job:
R=<run id>
gh run view "$R" --repo docs-plus/docs.plus --json jobs --jq '.jobs[] | "\(.name)\t" + ([.steps[] | select(.name | test("^Post Run ./.github/actions/setup-(bun|cypress)|^Post 🥟")) | "\(.name)=\(((.completedAt|fromdate)-(.startedAt|fromdate)))s"] | join(" "))'Reserve failures and the Bun version, per successful job:
for j in $(gh run view "$R" --repo docs-plus/docs.plus --json jobs --jq '.jobs[] | select(.conclusion == "success") | .databaseId'); do
log=$(gh api --allow-escape-sequences "repos/docs-plus/docs.plus/actions/jobs/$j/logs")
printf '%s reserve=%s %s\n' "$j" \
"$(grep -cE 'Unable to reserve cache with key Linux-(bun|cypress)' <<<"$log")" \
"$(grep -oE 'bun install v[0-9.]+' <<<"$log" | sort -u | tr '\n' ' ')"
doneCache usage, and new entries on PR refs:
gh api repos/docs-plus/docs.plus/actions/cache/usage
gh api --paginate "repos/docs-plus/docs.plus/actions/caches?per_page=100" --jq '.actions_caches[] | select(.key | test("^Linux-(bun|cypress)-")) | [.key, .ref, .size_in_bytes, .created_at] | @tsv'M2g (defined in #569):
gh run view "$R" --repo docs-plus/docs.plus --json createdAt,jobs --jq '(.createdAt|fromdate) as $t0 | .jobs[] | select(.name == "🏗️ Build Verification") | ((.completedAt|fromdate) - $t0)'Accountability
Record per SP3 (#554). Add the R1, R2 and chatroom run ids, and every table row below with its value. Add the reserve count and bun install v line per job. Add the cache usage 7 days after the merge.
| Metric | Read from | Baseline | Expected |
|---|---|---|---|
Post Run ./.github/actions/setup-cypress, per Ext job |
R1, R2 | 10–15 s (run 39398067267) | No such step, or 1 s or less |
setup-bun post step, per job |
R1, R2 | 5–21 s; 6–10 s on Ext jobs (run 39398067267) | 1 s or less (only oven-sh/setup-bun, 179 ms in job 118546569637) |
Unable to reserve cache with key Linux-(bun|cypress), whole run |
R2 | 10 (6 Cypress, 4 Bun, run 39398067267) | 0 |
| The same count | R1 | 10 | Record it. Jobs can race for the first save. |
bun install v per job, except 🚀 Deploy Production |
R1 | v1.4.3 (v1.4.1 in chatroom) |
v1.4.4 in every job |
active_caches_size_in_bytes |
7 days after the merge | 10480109180 in 87 entries |
Under 5000000000 (computed). v1 entries leave after 7 days unused. |
New Linux-bun/Linux-cypress entries on refs/pull/* |
after the first Dependabot PR run on the new code | 10 entries on PR refs | 0 |
| M2g, quick read only | the first deploy run with an Ext suite, other than R1 | median 538 s, 'Ext suite ran' slice (#569) | Record it. About 10–25 s lower; set B siblings move it too. |
| M6 (#569) | the first PR run on the new code | PR median 519 s |
Record it. Not judged here. |
| M1, M2i, M3, M4, M5, W (#569) | — | — | Not judged here. |
- Stop condition, revert. R1 or R2 fails in one of these steps, and a re-run fails the same way:
🏷️ Read Cypress version,📦 Restore …,📥 Install Dependencies,🌲 Install Cypress binary,🔎 Look up …or💾 Save …;- any suite that passed on
d0a53756f8676556358b6adc6c2397d2ed7c64c8and now fails only under the pinned Bun.
- Fix forward, do not revert, when the only problem is a nonzero reserve count or cache usage over the target.
Unable to reserve cachefails no job. Comment here with the numbers.
Rollback
- Revert per SP4 ([Tracking] Faster, change-aware CI/CD pipeline #554), on the stop condition in Accountability. No deploy is needed.
- If change set B landed as one commit, restore only this issue's files:
git checkout <commit>^ -- .github/actions/setup-bun/action.yml .github/actions/setup-cypress/action.yml;- in
.github/WORKFLOWS.md, undo only the Step 5 lines by hand, because Start the extension and webapp unit tests without waiting for backend validation #558 also edits that file; - in
chatroom-e2e.yml, re-add only thewith:andbun-version: '1.4.1'lines.
- No host step and no repository setting is involved.
- Entries saved under the new keys do no harm after the revert. GitHub removes them after 7 days without use.
Docs to update
.github/WORKFLOWS.md:96(Step 5).- No
CHANGELOG.mdentry. This changes CI only, and no package or product ships from it.
Out of scope
.github/actions/build-extensions. Itsext-v3-…entries are about 0.01 GB. Leave it unchanged.stage.docs.plus.yml: Remove the stage pipeline and stage notes, because stage no longer exists #725 removes it.- The
oven-sh/setup-bunbinary entry (35689541bytes). Leave it. - Dockerfiles. They keep
oven/bun:1-slimwith no Bun patch tag (AGENTS.md:288-289). The pin applies to CI runners only. - The Bun floor. Do not change
AGENTS.md:66(Bun >= 1.4.0) orpackage.jsonengines. - A
bun.lockchange is not part of this issue. .next/cachein CI and atsbuildinfocache. The tracker's Not doing list rejects both.- Path filters and suite scoping (Stop extension README media from triggering extension test suites #562, Run only the CI suites a pull request or push can affect #563), and the run timing table (Write a timing table to every CI/CD run summary #556).
- Deleting cache entries by hand. No new PR entries arrive after the merge, and GitHub removes entries not used for 7 days.
- A single named job that saves the Bun cache. The lookup step already skips a key that another job saved. On the first push that changes
bun.lock, run the reserve-failure command in Verification and comment here with the count. Do this before you add a new input. - Tests. R1 and R2 verify this CI-only change.
Read first
- [Tracking] Faster, change-aware CI/CD pipeline #554
AGENTS.md§Package Manager (lines 57-66) and §Docker (lines 286-297).github/actions/setup-bun/action.yml,.github/actions/setup-cypress/action.yml,.github/actions/build-extensions/action.yml.github/workflows/prod.docs.plus.ymllines 1-60, 201-300 and 350-372.github/workflows/chatroom-e2e.yml,.github/workflows/lockstep-guard.yml,.github/workflows/backend-ci.yml,.github/workflows/quality-lint.yml.github/filters/extensions.yamllines 1-20.github/dependabot.ymllines 1-28.github/WORKFLOWS.mdactions/cacherestore/action.ymlandsave/action.ymlat55cc8345863c7cc4c66a329aec7e433d2d1c52a9
Amended 2026-11-06 (maintainer ruling): the Bun pin items read 1.4.4, after 72f08af7a (#650, #651). Measured history above keeps its original 1.4.1 values.
Activity
HMarzban commentedon Oct 26, 2026
Built and committed on local main. Awaits the maintainer's final push.
Remaining gate: the push only. Then runs R1 and R2, the cache usage 7 days after the merge, and the SP3 comment.
ci: restore-then-save the Bun and Cypress caches and pin Bun 1.4.1
HMarzban commentedon Nov 3, 2026
Status, 2026-11-03.
e3b4a213ais pushed and deployed on 2026-11-03. R1 is run 41608014517 plus chatroom run 41608014389. Every hosted job logsbun install v1.4.1.🔒 Security Auditsaved nothing. R1 had 2 reserve failures, and the issue says to record that count only.Left:
bun.lock. It must show 0 reserve failures.HMarzban commentedon Nov 3, 2026
Measured, 2026-11-03.
Run: 41608014517, attempt 1 (R1), with chatroom run 41608014389.
On main: #555–#565. #566 has only its temporary
backend_no_cacheinput (a9688f0). #568 has only its trace tooling (d9b6222).M1 598 | M2g 496 | M2i 509 | M3 445 | M4 7 | M5 59 | W 9 | free_gb 60 | cached_installs 0
Expected: no cache post step; 0 reserve failures in R2;
bun install v1.4.1in every hosted job; cache under5000000000bytes 7 days after the merge.Verdict: keep.
R2 has not happened yet. R2 needs an Ext suite and an unchanged
bun.lock. Both later deploys changedbun.lock:So neither run is R2.
Reserve failures. The regex is
Unable to reserve cache with key Linux-(bun|cypress), counted on successful jobs, as in Verification.Linux-bun-v2-1.4.1-d24e41…(job 125822714390, lint)Linux-bun-v2-1.4.1-d24e41…Linux-cypress-16.2.0Linux-bun-v2-1.4.1-93c094…, 6Linux-cypress-16.2.1Linux-bun-v2-1.4.1-93c094…andLinux-cypress-16.2.1Linux-bun-v2-1.4.1-07eb8d…Linux-bun-v2-1.4.1-07eb8d…The chatroom and editor counts include failed jobs. Those runs failed in their suites, not in a cache step.
Out of scope asks for the count on the first push that changes
bun.lock. It is 10 in run 41626334830, the same as the old baseline. In both lock-change runs, the gate jobs missed the new key, and the lookup found no entry. Each job then tried to save, and the reserve failed. For example, in run 41626334830:Cache not foundfor the lookup at 11:18:30;Linux-bun-v2-1.4.1-93c094…entry was created at 11:18:31;Unable to reserveat 11:18:40.Editor Browser Tests(added in cfb5bc8) saved the entry in both lock-change runs. It is a new caller ofsetup-bunandsetup-cypressthat item 10 does not list. This is fix-forward data, not a stop condition. No job failed because of it.Post-step seconds:
Post Run ./.github/actions/setup-cypressstep, in any of the three deploys.Post Run ./.github/actions/setup-bunon the 6 Ext jobs: 0–1 s in all three deploys.Post 🥟 Setup Environmenton the other gate jobs: 0–1 s, except🔒 Security Auditin R1 at 2 s. The target is 1 s or less.Bun version: every hosted job that runs
setup-bunlogsbun install v1.4.1, in all three deploys and both PR runs.🧱 Build Imageslogsbun install v1.4.4. That is theoven/bun:1-slimimage build, now moved out of🚀 Deploy Productionby #565. Theimagesjob never callssetup-bun.PR-ref entries: proven. The first Dependabot PR runs on the new code were 41626692066 and 41637030759, both on #674. Every entry created on
refs/pull/674/mergeon 2026-11-03 starts withext-v3-. No entry on anyrefs/pull/*ref matches^Linux-bun-v2-or^Linux-cypress-[0-9]+\.[0-9]+\.[0-9]+$. TheLinux-bun-v1-1.4.4-…andLinux-cypress-<hash>entries on PRs 672–676 were created on 2026-11-01, before the change.Cache usage, interim:
active_caches_size_in_bytes7977152624 in 144 entries, read on 2026-11-03. The gate read is due on or after 2026-11-10.M2g quick read: run 41626334830 is the first deploy with an Ext suite after R1. M2g is 348 s (
🏗️ Build Verification, job 125886115400). The baseline median is 538 s. Set B siblings also move it.M6 on the first PR run: 192 s in run 41626692066 (
📊 Run Report, job 125887166572). That run failed at📝 Type Check(job 125885865695), so it is not a clean sample. Not judged here.Can close now: no — R2 (the next push with an Ext suite and an unchanged
bun.lock, with 0 reserve failures), and the cache usage read on or after 2026-11-10.HMarzban commentedon Nov 3, 2026
Status, 2026-11-03 (after the 1b05cb2 deploy).
R2 is run 41677887088, attempt 1,
success. Two Ext suites ran, andbun.lockdid not change since3298c7f83.Verification loop on all 14 successful jobs:
Unable to reserve cache with key Linux-(bun|cypress): 0 in every job. Pass.Linux-bun-v2-1.4.1-07eb8d…. Both Ext jobs restoredLinux-cypress-16.2.1. No job saved aLinux-bunorLinux-cypressentry.ext-v3-keys loggedUnable to reserve, in Type Check (126063631759) and Backend E2E (126063632067). The regex does not cover them, and no job failed.With R2 and the earlier PR-ref proof, every acceptance checkbox now passes.
Cache usage, interim:
active_caches_size_in_bytes7978234751 in 148 entries, read at 17:52:07Z.Left: the Accountability read of cache usage on or after 2026-11-10. The target is under
5000000000.HMarzban commentedon Nov 4, 2026
Status, 2026-11-04. Two acceptance items now read false on
main. "Defaults to 1.4.1" and "bun install v1.4.1" changed when72f08af7a(#650, #651) movedsetup-bunandlockstep-guard.ymlto Bun 1.4.4.active_caches_size_in_bytes. It must be under 5000000000. The read on 2026-11-04 was 9035372445 bytes in 163 entries, while the old 1.4.1 keys age out.HMarzban commentedon Nov 6, 2026
Maintainer ruling, 2026-11-06
The acceptance list is amended in the issue body. Each changed line is marked with this date.
HMarzban commentedon Nov 6, 2026
Interim read, 2026-11-06 (not the close read).
active_caches_size_in_bytesis 9539340517 in 172 entries. It was 9035372445 in 163 entries on 2026-11-04. The total is still above 5000000000, but the excess is old entries that nothing uses any more:Linux-bun-v1-1.4.4-…(5 on Dependabot PR refs #672–#676, 1 onmain)Linux-cypress-<hash>(old key shape)Linux-bun-v2-1.4.1-…(old Bun pin)Linux-cypress-16.2.0GitHub removes a cache that nobody has used for 7 days. Once these age out, about 1.9 GB of live entries are left (
Linux-bun-v2-1.4.4,Linux-cypress-16.2.1, the smallext-v3keys). No newLinux-bun-v1or PR-refLinux-bun-v2entry was created after 2026-11-01.Next read: after 2026-11-10 17:00Z, when the last old entry has aged out.
HMarzban commentedon Nov 11, 2026
Measured, close read, 2026-11-11.
gh api repos/docs-plus/docs.plus/actions/cache/usage, read at 16:21Z:{"active_caches_size_in_bytes":3298092956,"active_caches_count":76}Live size per key prefix, from the entry list:
Linux-bun-v2-1.4.4-…mainLinux-cypress-16.2.1mainbun-…(oven-sh/setup-bunbinary)mainext-v3-…mainThe drop comes from fewer large entries. The old
Linux-bun-v1-…,Linux-bun-v2-1.4.1-…,Linux-cypress-<hash>andLinux-cypress-16.2.0entries aged out after 7 days unused, as the 2026-11-06 read predicted. No entry of any kind sits on arefs/pull/*ref.Reserve failures. 0 on unchanged-lock runs (R2, run 41677887088). Lock-change runs still race: 10 and 8 (runs 41626334830, 41636667896). They fail no job. A single-saver job stays out of scope (#554 ruling 16). #653 cuts how often
bun.lockchanges.Gate path. The effect on M2g is not isolated; #569 owns M2g. Take the slowest Ext job of the last 5 push runs with an Ext suite (42689997917, 42656885466, 42626416956, 42582921035, 42363595092). Its setup post steps took 0 s on 5 of 5: median 0 s, range 0–0 s. Every setup post step on the 13 push runs from 2026-11-07 to 2026-11-11 took 0–1 s. Before: 5–21 s per job (run 39398067267).
M6 on Dependabot PR runs that changed
bun.lock(a record, not a gate). Successful attempt-1 runs only. M6 is the runcreatedAtto the last successful jobcompletedAt, without the report job (#569).e3b4a213a). Median 515 s, range 386–603 s, n = 3. The other four Dependabot PR runs on the new code failed, so they are left out.Bun pin. Step 3 now reads 1.4.4 in the body. It shipped at 1.4.1 in
e3b4a213a, and #650 moved it to 1.4.4 in72f08af7a.Every acceptance item passes. This issue can close as completed.