Skip to content

Keep the Actions cache under its limit and pin Bun in CI #561

Closed

Description

@HMarzban

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-bun and .github/actions/setup-cypress use actions/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 Audit job saves an --ignore-scripts tree under the shared key.
  • After. Both actions restore with actions/cache/restore and save with actions/cache/save only on a primary-key miss, never on pull_request. Bun is pinned to 1.4.4 in 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

Current behaviour

Links are pinned to d0a53756f8676556358b6adc6c2397d2ed7c64c8.

  1. setup-bun defaults to latest (setup-bun/action.yml:11-20).
    • bun-version has default: 'latest'. No caller passes cache-version, so every key uses v1. In run 39398067267 every gate job logged Downloading a new version of Bun: https://github.com/oven-sh/bun/releases/download/bun-v1.4.3/bun-linux-x64.zip.
  2. setup-bun caches with actions/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 latest default, which the pin ends, and native addons, which stay.
    • The repo has one lockfile, the root bun.lock (dependabot.yml:19-23).
  3. The security job saves an --ignore-scripts tree under the shared key.
    • prod.docs.plus.yml:230-233 passes ignore-scripts: 'true'. The key does not encode that input.
    • In job 118545695054, bun install --frozen-lockfile --ignore-scripts ran at 09:05:37. The post step logged Cache saved with key: Linux-bun-v1-1.4.3-6e2b83abc8e667f5f7ced75c74f6e0269d7a685e5e5ba25f0684f29179390e59 at 09:05:57.
    • The 6 Ext jobs, 🧪 Webapp Unit Tests and 🏗️ Build Verification then 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.
  4. setup-cypress keys the binary on bun.lock and restores by prefix (setup-cypress/action.yml:24-31).
    • key: ${{ runner.os }}-cypress-${{ hashFiles('**/bun.lock') }} and restore-keys: ${{ runner.os }}-cypress-.
    • Every bun.lock change makes a new key, even when Cypress stays the same. In run 39398067267 every Ext job missed Linux-cypress-6e2b83ab…, restored Linux-cypress-85af30df… by prefix, and found Cypress 15.21.1 is installed.
    • **/bun.lock walks the restored node_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-hyperlink on purpose (setup-cypress/action.yml:8-15, :33-43).
  5. 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 (457591034 bytes) by prefix. It then logged Installing Cypress (version: 16.2.0). The entry saved on refs/pull/540/merge is 683165434 bytes, so it holds both binaries.
  6. 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).
  7. Post-step seconds in run 39398067267, from gh run view 39398067267 --json jobs. 🏗️ Build Verification waits for every Ext job, so the Ext post steps sit on the gate path.
    • setup-cypress post: 10–15 s on each of the 6 🧪 Ext (…) jobs.
    • setup-bun post: 6–10 s on Ext jobs; 🧪 Backend Tests 21 s, 🔒 Security Audit 18 s, 📝 Type Check 14 s, 🔍 Lint & Format 14 s, 🧪 Backend E2E 11 s, 🧪 Webapp Unit Tests 8 s, 🏗️ Build Verification 5 s.
    • On an exact hit the Bun post step only logs not saving cache. It still took 7.9 s in job 118546569637, of which oven-sh/setup-bun took 179 ms.
  8. The cache on 2026-10-20. gh api repos/docs-plus/docs.plus/actions/cache/usage returned 10480109180 bytes in 87 entries. 65 sit on Dependabot PR refs (refs/pull/534/merge to refs/pull/540/merge). By key prefix, from gh api repos/docs-plus/docs.plus/actions/caches:
    • Linux-bun: 4 entries on main (3.56 GB), 5 on refs/pull/* (3.43 GB). main holds Linux-bun-v1-1.4.3-… (683305960 bytes) and Linux-bun-v1-1.4.1-… (1099659056 bytes) per lock hash. The 1.4.1 entries come from chatroom-e2e.yml, whose post step saves after the suite.
    • Linux-cypress: 2 on main (0.92 GB), 5 on refs/pull/* (2.51 GB).
    • ext-v3 (from .github/actions/build-extensions): 55 on refs/pull/* (0.01 GB), 15 on main (under 0.01 GB).
    • bun-+CxZWfwTi+/AufZaQ1DSt6rSdDY= (from oven-sh/setup-bun): 1 on main (0.04 GB).
  9. Two workflows already pin Bun 1.4.1.
    • chatroom-e2e.yml:54-57 passes bun-version: '1.4.1' to setup-bun.
    • lockstep-guard.yml:32-35 calls oven-sh/setup-bun directly with bun-version: '1.4.1'.
    • Chatroom run 39398067266 logged bun install v1.4.1 (4661e494f) on the current bun.lock with --frozen-lockfile, and succeeded.
    • The prod image build in deploy job 118549257854 logged bun install v1.4.3 (c6da4a4d3) 7 times.
    • bun-types is ^1.4.2 (package.json:105), locked at bun-types@1.4.2.
  10. The callers. setup-bun is used at prod.docs.plus.yml:206, :231, :293, :327 and :385; backend-ci.yml:26 and :85; quality-lint.yml:21; chatroom-e2e.yml:54; and stage.docs.plus.yml:68, :86 (with ignore-scripts: 'true' at :88), :116, :142 and :168.
    • Added after the pinned commit: editor-e2e.yml (setup-bun and setup-cypress, added in cfb5bc8e4) and supabase-policies.yml (setup-bun).
    • setup-cypress is used at prod.docs.plus.yml:297, chatroom-e2e.yml:57 and stage.docs.plus.yml:122. Each caller runs setup-bun first.
    • No caller reads setup-bun's cache-hit output.
    • 🏗️ Build Verification lists extension-tests in needs (prod.docs.plus.yml:355-365).
    • extensions.yaml:13-15 lists both actions as shared inputs, so a push that edits them runs every Ext suite.
  11. The pinned actions/cache SHA has both sub-actions. Tag v6.1.0 is commit 55cc8345863c7cc4c66a329aec7e433d2d1c52a9.

Target behaviour

  • No cache post step in either action. The Post Run ./.github/actions/setup-bun step keeps only the oven-sh/setup-bun part, about 0.2 s.
  • Pull request runs restore and never save a Linux-bun-… or Linux-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. v2 drops every old entry, including the --ignore-scripts tree.
  • Cypress key: Linux-cypress-<installed Cypress version>, for example Linux-cypress-15.21.1, with no restore-keys.
  • Bun version. Every setup-bun job and lockstep-guard.yml run 1.4.4. chatroom-e2e.yml has no override.
  • Cache usage stays under 5000000000 bytes 7 days after the merge. This is computed: one Bun entry of 683305960 to 1099659056 bytes per lock hash used in 7 days, plus one 457591034-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

  1. 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
  2. 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 reads setup-bun's cache-hit output, or calls setup-cypress before setup-bun.
  3. Confirm the actions/cache pin.

    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 bumped actions/cache on main, use the SHA in build-extensions/action.yml and repeat the restore/action.yml check on it.
  4. Record the actionlint baseline.

    actionlint -config-file .github/actionlint.yaml
    • At the pinned commit it exits 1 with 4 findings: two SC2016 in discord-release.yml:156, one SC2016 in lockstep-guard.yml:38, and the unknown stage.docs.plus label in stage.docs.plus.yml:194. Write down your list for Step 6.

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. The cache-hit output at lines 22-25 reads steps.cache.outputs.cache-hit, and actions/cache/restore sets 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 old 1099659056-byte chatroom entry, so the save path never runs. The first run pays one cold bun install per 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.

  1. In .github/actions/setup-bun/action.yml, replace the three bun-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'
  2. .github/workflows/lockstep-guard.yml:35 reads bun-version: '1.4.4'. Make no change there.

  3. 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/*/docker

Expect 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.yml

Expect 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.md
  • actionlint shows the Step 0.4 findings and nothing new. It does not read composite action.yml files, so the YAML line checks them: 5 steps for 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 _shared inputs in .github/filters/extensions.yaml, so that push runs every Ext suite.

Acceptance criteria

  • setup-bun and setup-cypress contain no actions/cache@ line. Each uses actions/cache/restore and actions/cache/save, pinned by full SHA.
  • The Bun key uses hashFiles('bun.lock'). The Cypress key is ${{ runner.os }}-cypress-<version> and has no restore-keys.
  • The save steps are skipped on pull_request, on an exact hit, after a lookup hit, and for ignore-scripts: 'true'.
  • cache-version defaults to v2. In R1, 🔒 Security Audit saves nothing. In R1 or its chatroom run, one job saves a Linux-bun-v2-… entry.
  • setup-bun defaults to 1.4.4, and lockstep-guard.yml reads 1.4.4.
  • chatroom-e2e.yml passes no bun-version to setup-bun.
  • No Dockerfile changed. The images stay on oven/bun:1-slim.
  • actionlint shows no new findings beyond the Step 0.4 baseline.
  • .github/WORKFLOWS.md states 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-bun or Unable to reserve cache with key Linux-cypress.
  • In R1, every job that runs setup-bun logs bun install v1.4.4. 🚀 Deploy Production is excluded, because its image build uses oven/bun:1-slim.
  • No cache entry on a refs/pull/* ref has a key that starts with Linux-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.yml push run on main with this change in which the 🧪 Ext jobs ran, plus the chatroom-e2e.yml run 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 dependencies after the Bun save shows 💾 Save Dependencies as skipped.
  • R2 is the next push run on main where at least one Ext suite ran and bun.lock did 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' ' ')"
done

Cache 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 d0a53756f8676556358b6adc6c2397d2ed7c64c8 and 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 cache fails no job. Comment here with the numbers.

Rollback

  1. Revert per SP4 ([Tracking] Faster, change-aware CI/CD pipeline #554), on the stop condition in Accountability. No deploy is needed.
  2. If change set B landed as one commit, restore only this issue's files:
  3. No host step and no repository setting is involved.
  4. 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.md entry. This changes CI only, and no package or product ships from it.

Out of scope

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.yml lines 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.yaml lines 1-20
  • .github/dependabot.yml lines 1-28
  • .github/WORKFLOWS.md
  • actions/cache restore/action.yml and save/action.yml at 55cc8345863c7cc4c66a329aec7e433d2d1c52a9

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

  1. added this to the v2.3.0 milestone on Oct 20, 2026
  2. HMarzban commented on Oct 26, 2026

    @HMarzban
    CollaboratorAuthor

    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.

  3. HMarzban commented on Nov 3, 2026

    @HMarzban
    CollaboratorAuthor

    Status, 2026-11-03. e3b4a213a is pushed and deployed on 2026-11-03. R1 is run 41608014517 plus chatroom run 41608014389. Every hosted job logs bun install v1.4.1. 🔒 Security Audit saved nothing. R1 had 2 reserve failures, and the issue says to record that count only.

    Left:

    • Builder: read R2, the next push with an Ext suite and an unchanged bun.lock. It must show 0 reserve failures.
    • Builder: read the cache usage on or after 2026-11-10.
    • Builder: check the PR-ref entries after the first Dependabot PR run.
    • Builder: post the SP3 comment.
  4. HMarzban commented on Nov 3, 2026

    @HMarzban
    CollaboratorAuthor

    Measured, 2026-11-03.
    Run: 41608014517, attempt 1 (R1), with chatroom run 41608014389.
    On main: #555–#565. #566 has only its temporary backend_no_cache input (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.1 in every hosted job; cache under 5000000000 bytes 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 changed bun.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.

    Run Prod workflow Keys Chatroom run Editor run
    41608014517 (R1) 1 1 Linux-bun-v2-1.4.1-d24e41… (job 125822714390, lint) 41608014389: 1; it saved Linux-bun-v2-1.4.1-d24e41… 41608014402: 1; it saved Linux-cypress-16.2.0
    41626334830 (lock changed) 10 4 Linux-bun-v2-1.4.1-93c094…, 6 Linux-cypress-16.2.1 41626334638 (failed): 2 41626334725 (failed): 0; it saved Linux-bun-v2-1.4.1-93c094… and Linux-cypress-16.2.1
    41636667896 (lock changed) 8 8 Linux-bun-v2-1.4.1-07eb8d… 41636667720 (failed): 1 41636667683 (failed): 0; it saved Linux-bun-v2-1.4.1-07eb8d…
    41626692066, 41637030759 (PR) 0, 0 — — —

    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:

    • job 125884636825 logged Cache not found for the lookup at 11:18:30;
    • the Linux-bun-v2-1.4.1-93c094… entry was created at 11:18:31;
    • the job's save then failed with Unable to reserve at 11:18:40.

    Editor Browser Tests (added in cfb5bc8) saved the entry in both lock-change runs. It is a new caller of setup-bun and setup-cypress that item 10 does not list. This is fix-forward data, not a stop condition. No job failed because of it.

    Post-step seconds:

    • No job has a Post Run ./.github/actions/setup-cypress step, in any of the three deploys.
    • Post Run ./.github/actions/setup-bun on the 6 Ext jobs: 0–1 s in all three deploys.
    • Post 🥟 Setup Environment on the other gate jobs: 0–1 s, except 🔒 Security Audit in R1 at 2 s. The target is 1 s or less.

    Bun version: every hosted job that runs setup-bun logs bun install v1.4.1, in all three deploys and both PR runs. 🧱 Build Images logs bun install v1.4.4. That is the oven/bun:1-slim image build, now moved out of 🚀 Deploy Production by #565. The images job never calls setup-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/merge on 2026-11-03 starts with ext-v3-. No entry on any refs/pull/* ref matches ^Linux-bun-v2- or ^Linux-cypress-[0-9]+\.[0-9]+\.[0-9]+$. The Linux-bun-v1-1.4.4-… and Linux-cypress-<hash> entries on PRs 672–676 were created on 2026-11-01, before the change.

    Cache usage, interim: active_caches_size_in_bytes 7977152624 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.

  5. HMarzban commented on Nov 3, 2026

    @HMarzban
    CollaboratorAuthor

    Status, 2026-11-03 (after the 1b05cb2 deploy).

    R2 is run 41677887088, attempt 1, success. Two Ext suites ran, and bun.lock did not change since 3298c7f83.

    Verification loop on all 14 successful jobs:

    • Unable to reserve cache with key Linux-(bun|cypress): 0 in every job. Pass.
    • Every gate job restored Linux-bun-v2-1.4.1-07eb8d…. Both Ext jobs restored Linux-cypress-16.2.1. No job saved a Linux-bun or Linux-cypress entry.
    • The setup post steps took 0–1 s.
    • Two ext-v3- keys logged Unable 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_bytes 7978234751 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.

  6. HMarzban commented on Nov 4, 2026

    @HMarzban
    CollaboratorAuthor

    Status, 2026-11-04. Two acceptance items now read false on main. "Defaults to 1.4.1" and "bun install v1.4.1" changed when 72f08af7a (#650, #651) moved setup-bun and lockstep-guard.yml to Bun 1.4.4.

    • [maintainer] Amend the Bun-pin items to 1.4.4, citing Run CI on Bun 1.4.4, the version production ships #650.
    • On or after 2026-11-10, read 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.
  7. HMarzban commented on Nov 6, 2026

    @HMarzban
    CollaboratorAuthor

    Maintainer ruling, 2026-11-06

    The acceptance list is amended in the issue body. Each changed line is marked with this date.

  8. HMarzban commented on Nov 6, 2026

    @HMarzban
    CollaboratorAuthor

    Interim read, 2026-11-06 (not the close read).

    active_caches_size_in_bytes is 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:

    Key prefix Size Entries Last used GitHub drops it after
    Linux-bun-v1-1.4.4-… (5 on Dependabot PR refs #672–#676, 1 on main) 3.75 GB 6 2026-11-01 18:14Z about 2026-11-08 18:14Z
    Linux-cypress-<hash> (old key shape) 1.35 GB 6 2026-11-01 18:14Z about 2026-11-08 18:14Z
    Linux-bun-v2-1.4.1-… (old Bun pin) 2.35 GB 3 2026-11-03 16:53Z about 2026-11-10 16:53Z
    Linux-cypress-16.2.0 0.23 GB 1 2026-11-03 09:11Z about 2026-11-10 09:11Z

    GitHub 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 small ext-v3 keys). No new Linux-bun-v1 or PR-ref Linux-bun-v2 entry was created after 2026-11-01.

    Next read: after 2026-11-10 17:00Z, when the last old entry has aged out.

  9. modified the milestones: v2.3.0, v2.3.6 on Nov 9, 2026
  10. HMarzban commented on Nov 11, 2026

    @HMarzban
    CollaboratorAuthor

    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}
    • 3,298,092,956 B is under the 5,000,000,000 B target. Pass.
    • Before: 10,480,109,180 B in 87 entries (2026-10-20). That is 69 % smaller.

    Live size per key prefix, from the entry list:

    Key prefix Size Entries Ref
    Linux-bun-v2-1.4.4-… 3,000,370,312 B 6 main
    Linux-cypress-16.2.1 225,703,061 B 1 main
    bun-… (oven-sh/setup-bun binary) 50,544,726 B 1 main
    ext-v3-… 21,474,857 B 68 main

    The drop comes from fewer large entries. The old Linux-bun-v1-…, Linux-bun-v2-1.4.1-…, Linux-cypress-<hash> and Linux-cypress-16.2.0 entries aged out after 7 days unused, as the 2026-11-06 read predicted. No entry of any kind sits on a refs/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.lock changes.

    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 run createdAt to the last successful job completedAt, without the report job (#569).

    • Before: 461, 490, 496, 534 and 579 s (runs 39274590009, 39274647538, 39275480131, 39284030984, 39970841653; 2026-10-19 to 2026-10-23). Median 496 s, range 461–579 s, n = 5.
    • After: 386, 515 and 603 s (runs 41608282825, 41608350449, 41608349286; all 2026-11-03, on heads that contain 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.
    • The after median is 19 s above the before. That is under the 60 s follow-up bar, so no ruling is needed.

    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 in 72f08af7a.

    Every acceptance item passes. This issue can close as completed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions