@@ -43,10 +43,6 @@ inputs:
4343 snapshot.
4444 required : false
4545 default : " false"
46- runtime-cache-sticky-disk :
47- description : Whether runtime caches should use Blacksmith sticky disks instead of actions/cache.
48- required : false
49- default : " false"
5046 vitest-fs-cache :
5147 description : Whether to persist Vitest's experimental filesystem module cache.
5248 required : false
@@ -64,10 +60,7 @@ inputs:
6460 required : false
6561 default : " false"
6662 save-vitest-fs-cache :
67- description : >
68- Whether this job may save the shared Vitest filesystem module cache.
69- Only honored outside pull_request events for sticky disks; PR jobs
70- always mount the protected snapshot read-only.
63+ description : Whether this job may save the shared Vitest filesystem module cache.
7164 required : false
7265 default : " false"
7366 build-all-cache-scope :
@@ -122,15 +115,15 @@ runs:
122115
123116 - name : Mount dependency sticky disk
124117 if : inputs.sticky-disk == 'true'
125- uses : useblacksmith/stickydisk@5b350170ae4ef55b536b548ef5f5896e76a6b54f # v1.4.0
118+ uses : useblacksmith/stickydisk@6d373c96a74cbde0c99fedc5ea5d3a7ba66ba494 # main (post- v1.4.0 hot-attach fix)
126119 with :
127- # One stable disk per Node line. v4 resets the v3 lineage after
128- # Blacksmith repeatedly acknowledged commits but kept restoring its
129- # original snapshot. The v2 per-PR/per-manifest-hash keys
120+ # One stable disk per Node line. v5 starts a fresh lineage for the
121+ # preflight-serialized writer after Blacksmith acknowledged repeated v4
122+ # commits but kept restoring its original snapshot. The v2 per-PR/per-manifest-hash keys
130123 # saturated Blacksmith's installation-wide sticky-disk budget. Install
131124 # inputs, runner platform, and the exact Node patch live in the runtime
132125 # marker below, so changes refresh this disk in place.
133- key : ${{ github.repository }}-node-deps-bind-v4 -${{ inputs.node-version }}
126+ key : ${{ github.repository }}-node-deps-bind-v5 -${{ inputs.node-version }}
134127 path : /var/tmp/openclaw-node-deps
135128 # Single semantic writer: only the designated trusted-push job may
136129 # commit, so pull_request clones stay read-only. Like every sticky
@@ -139,58 +132,37 @@ runs:
139132 # and same-repo PR authors already hold repository write access.
140133 # Explicit true (not on-change) because the allocated-byte heuristic
141134 # can miss a fingerprint refresh whose reinstall keeps disk usage
142- # stable, permanently stranding consumers on a stale marker. v1.4.0
143- # skips commit after failed/cancelled steps, so a broken install
144- # cannot seed this key.
135+ # stable, permanently stranding consumers on a stale marker. The action
136+ # skips commit after failed/cancelled steps, so a broken install cannot
137+ # seed this key.
145138 commit : ${{ inputs.save-sticky-disk == 'true' && github.event_name != 'pull_request' && 'true' || 'false' }}
146139
147- - name : Mount Vitest transform cache sticky disk
148- if : inputs.vitest-fs-cache == 'true' && (inputs.sticky-disk == 'true' || inputs.runtime-cache-sticky-disk == 'true') && runner.os != 'Windows'
149- uses : useblacksmith/stickydisk@5b350170ae4ef55b536b548ef5f5896e76a6b54f # v1.4.0
150- with :
151- # One stable disk per runner shape. The old per-PR overlay disks
152- # minted a new backing disk for every PR and helped saturate
153- # Blacksmith's installation-wide sticky-disk budget, 429-failing every
154- # mount. Cache entries are content-hash keyed (id+content+env), so PRs
155- # can safely read the protected snapshot directly; PR-local misses are
156- # rebuilt in the discarded mount. The generation guard below clears
157- # incompatible transform inputs without leaking one disk per lockfile.
158- key : ${{ github.repository }}-vitest-fs-v2-protected-${{ runner.os }}-${{ runner.arch }}-node-${{ inputs.node-version }}
159- path : /var/tmp/openclaw-vitest-fs-cache
160- # Single semantic writer: only the designated non-PR writer commits;
161- # pull_request mounts stay read-only clones. Explicit true avoids
162- # stickydisk's allocated-byte heuristic missing equal-size
163- # replacements or prune-balanced writes.
164- commit : ${{ inputs.save-vitest-fs-cache == 'true' && github.event_name != 'pull_request' && 'true' || 'false' }}
165-
166140 - name : Restore and save Vitest transform cache
167- if : inputs.vitest-fs-cache == 'true' && inputs.sticky-disk != 'true' && inputs.runtime-cache-sticky-disk != 'true' && inputs. save-vitest-fs-cache == 'true' && runner.os != 'Windows'
141+ if : inputs.vitest-fs-cache == 'true' && inputs.save-vitest-fs-cache == 'true' && runner.os != 'Windows'
168142 uses : actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5
169143 with :
170144 path : /var/tmp/openclaw-vitest-fs-cache
171- # actions/cache entries are immutable. One matrix job writes a new
172- # run key; every job restores the newest cache through coarse prefixes.
173- key : ${{ github.repository }}-vitest-fs-v2-${{ github.event_name == 'pull_request' && format('pr-{0}', github.event.pull_request.number) || 'protected' }}-${{ runner.os }}-${{ runner.arch }}-node-${{ inputs.node-version }}-${{ hashFiles('pnpm-lock.yaml', 'pnpm-workspace.yaml', '**/package.json', '**/tsconfig*.json', 'vitest.config.*', 'test/vitest/**') }}-${{ github.run_id }}-${{ github.run_attempt }}
145+ # Blacksmith transparently accelerates the upstream Actions cache API.
146+ # The scheduled/dispatch warmer writes one immutable protected archive;
147+ # all CI shards restore it into isolated runner-local directories.
148+ key : ${{ github.repository }}-vitest-fs-v3-protected-${{ runner.os }}-${{ runner.arch }}-node-${{ inputs.node-version }}-${{ hashFiles('pnpm-lock.yaml', 'pnpm-workspace.yaml', '**/package.json', '**/tsconfig*.json', 'vitest.config.*', 'test/vitest/**', '!**/node_modules/**') }}-${{ github.run_id }}-${{ github.run_attempt }}
174149 restore-keys : |
175- ${{ github.repository }}-vitest-fs-v2-${{ github.event_name == 'pull_request' && format('pr-{0}', github.event.pull_request.number) || ' protected' }} -${{ runner.os }}-${{ runner.arch }}-node-${{ inputs.node-version }}-${{ hashFiles('pnpm-lock.yaml', 'pnpm-workspace.yaml', '**/package.json', '**/tsconfig*.json', 'vitest.config.*', 'test/vitest/**') }}-
150+ ${{ github.repository }}-vitest-fs-v3- protected-${{ runner.os }}-${{ runner.arch }}-node-${{ inputs.node-version }}-${{ hashFiles('pnpm-lock.yaml', 'pnpm-workspace.yaml', '**/package.json', '**/tsconfig*.json', 'vitest.config.*', 'test/vitest/**', '!**/node_modules /**') }}-
176151
177152 - name : Restore Vitest transform cache
178- if : inputs.vitest-fs-cache == 'true' && inputs.sticky-disk != 'true' && inputs.runtime-cache-sticky-disk != 'true' && inputs. save-vitest-fs-cache != 'true' && runner.os != 'Windows'
153+ if : inputs.vitest-fs-cache == 'true' && inputs.save-vitest-fs-cache != 'true' && runner.os != 'Windows'
179154 uses : actions/cache/restore@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5
180155 with :
181156 path : /var/tmp/openclaw-vitest-fs-cache
182- key : ${{ github.repository }}-vitest-fs-v2-${{ github.event_name == 'pull_request' && format('pr-{0}', github.event.pull_request.number) || ' protected' }} -${{ runner.os }}-${{ runner.arch }}-node-${{ inputs.node-version }}-${{ hashFiles('pnpm-lock.yaml', 'pnpm-workspace.yaml', '**/package.json', '**/tsconfig*.json', 'vitest.config.*', 'test/vitest/**') }}-${{ github.run_id }}-${{ github.run_attempt }}
157+ key : ${{ github.repository }}-vitest-fs-v3- protected-${{ runner.os }}-${{ runner.arch }}-node-${{ inputs.node-version }}-${{ hashFiles('pnpm-lock.yaml', 'pnpm-workspace.yaml', '**/package.json', '**/tsconfig*.json', 'vitest.config.*', 'test/vitest/**', '!**/node_modules /**') }}-${{ github.run_id }}-${{ github.run_attempt }}
183158 restore-keys : |
184- ${{ github.repository }}-vitest-fs-v2-${{ github.event_name == 'pull_request' && format('pr-{0}', github.event.pull_request.number) || ' protected' }} -${{ runner.os }}-${{ runner.arch }}-node-${{ inputs.node-version }}-${{ hashFiles('pnpm-lock.yaml', 'pnpm-workspace.yaml', '**/package.json', '**/tsconfig*.json', 'vitest.config.*', 'test/vitest/**') }}-
159+ ${{ github.repository }}-vitest-fs-v3- protected-${{ runner.os }}-${{ runner.arch }}-node-${{ inputs.node-version }}-${{ hashFiles('pnpm-lock.yaml', 'pnpm-workspace.yaml', '**/package.json', '**/tsconfig*.json', 'vitest.config.*', 'test/vitest/**', '!**/node_modules /**') }}-
185160
186161 - name : Configure Vitest transform cache
187162 if : inputs.vitest-fs-cache == 'true' && runner.os != 'Windows'
188163 env :
189- CACHE_GENERATION : ${{ hashFiles('pnpm-lock.yaml', 'pnpm-workspace.yaml', '**/package.json', '**/tsconfig*.json', 'vitest.config.*', 'test/vitest/**') }}
190- # Sticky PR mounts never commit, so pruning there would only burn
191- # shard wall clock on a discarded clone; non-sticky (actions/cache)
192- # writers still prune their PR-scoped archives.
193- CACHE_WRITER : ${{ inputs.save-vitest-fs-cache == 'true' && ((inputs.sticky-disk != 'true' && inputs.runtime-cache-sticky-disk != 'true') || github.event_name != 'pull_request') && '1' || '0' }}
164+ CACHE_GENERATION : ${{ hashFiles('pnpm-lock.yaml', 'pnpm-workspace.yaml', '**/package.json', '**/tsconfig*.json', 'vitest.config.*', 'test/vitest/**', '!**/node_modules/**') }}
165+ CACHE_WRITER : ${{ inputs.save-vitest-fs-cache == 'true' && '1' || '0' }}
194166 shell : bash
195167 run : |
196168 set -euo pipefail
@@ -202,9 +174,8 @@ runs:
202174 cache_generation="$(<"$generation_file")"
203175 fi
204176 cache_entry="$(find "$cache_root" -mindepth 1 -maxdepth 1 -print -quit)"
205- # Read-only PR mounts clear a mismatched generation too: the wipe only
206- # affects the discarded local clone, and mixing generations could
207- # false-hit transforms produced under incompatible tsconfig/lockfile.
177+ # Every restore is runner-local. Never mix incompatible transform
178+ # inputs even when an older archive was selected through a prefix.
208179 if [[ -n "$cache_entry" ]] && [[ "$cache_generation" != "$CACHE_GENERATION" ]]; then
209180 echo "Vitest transform inputs changed; clearing incompatible cache generation"
210181 find "$cache_root" -mindepth 1 -maxdepth 1 -exec rm -rf -- {} +
@@ -215,39 +186,42 @@ runs:
215186 echo "OPENCLAW_VITEST_FS_MODULE_CACHE_PATH=$cache_root" >> "$GITHUB_ENV"
216187 echo "OPENCLAW_VITEST_FS_MODULE_CACHE_WRITER=$CACHE_WRITER" >> "$GITHUB_ENV"
217188
218- - name : Mount Node compile cache sticky disk
219- if : inputs.node-compile-cache == 'true' && (inputs.sticky-disk == 'true' || inputs.runtime-cache-sticky-disk == 'true') && runner.os != 'Windows'
220- uses : useblacksmith/stickydisk@5b350170ae4ef55b536b548ef5f5896e76a6b54f # v1.4.0
221- with :
222- # Trusted PRs read the protected dependency bytecode seed but cannot
223- # publish feature-branch code into it. Node isolates exact versions and
224- # invalidates bytecode when module contents change.
225- key : ${{ github.repository }}-node-compile-v2-${{ inputs.node-compile-cache-scope }}-protected-${{ runner.os }}-${{ runner.arch }}-node-${{ inputs.node-version }}
226- path : /var/tmp/openclaw-node-compile-cache
227- commit : ${{ inputs.save-node-compile-cache == 'true' && github.event_name != 'pull_request' && 'true' || 'false' }}
189+ - name : Select Node compile cache epoch
190+ id : node-compile-cache-epoch
191+ if : inputs.node-compile-cache == 'true' && runner.os != 'Windows'
192+ shell : bash
193+ env :
194+ CACHE_SCOPE : ${{ inputs.node-compile-cache-scope }}
195+ run : |
196+ set -euo pipefail
197+ if [ "$CACHE_SCOPE" = "build" ]; then
198+ echo "value=$(date -u +%Y%m%d)" >> "$GITHUB_OUTPUT"
199+ else
200+ echo "value=${GITHUB_RUN_ID:?}-${GITHUB_RUN_ATTEMPT:?}" >> "$GITHUB_OUTPUT"
201+ fi
228202
229203 - name : Restore and save Node compile cache
230- if : inputs.node-compile-cache == 'true' && inputs.sticky-disk != 'true' && inputs.runtime-cache-sticky-disk != 'true' && inputs. save-node-compile-cache == 'true' && runner.os != 'Windows'
204+ if : inputs.node-compile-cache == 'true' && inputs.save-node-compile-cache == 'true' && runner.os != 'Windows'
231205 uses : actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5
232206 with :
233207 path : /var/tmp/openclaw-node-compile-cache
234- key : ${{ github.repository }}-node-compile-v2 -${{ inputs.node-compile-cache-scope }}-${{ github.event_name == 'pull_request' && format('pr-{0}', github.event.pull_request.number) || ' protected' }} -${{ runner.os }}-${{ runner.arch }}-node-${{ inputs.node-version }}-${{ github.run_id }}-${{ github.run_attempt }}
208+ key : ${{ github.repository }}-node-compile-v3 -${{ inputs.node-compile-cache-scope }}-protected-${{ runner.os }}-${{ runner.arch }}-node-${{ inputs.node-version }}-${{ steps.node-compile-cache-epoch.outputs.value }}
235209 restore-keys : |
236- ${{ github.repository }}-node-compile-v2 -${{ inputs.node-compile-cache-scope }}-${{ github.event_name == 'pull_request' && format('pr-{0}', github.event.pull_request.number) || ' protected' }} -${{ runner.os }}-${{ runner.arch }}-node-${{ inputs.node-version }}-
210+ ${{ github.repository }}-node-compile-v3 -${{ inputs.node-compile-cache-scope }}-protected-${{ runner.os }}-${{ runner.arch }}-node-${{ inputs.node-version }}-
237211
238212 - name : Restore Node compile cache
239- if : inputs.node-compile-cache == 'true' && inputs.sticky-disk != 'true' && inputs.runtime-cache-sticky-disk != 'true' && inputs. save-node-compile-cache != 'true' && runner.os != 'Windows'
213+ if : inputs.node-compile-cache == 'true' && inputs.save-node-compile-cache != 'true' && runner.os != 'Windows'
240214 uses : actions/cache/restore@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5
241215 with :
242216 path : /var/tmp/openclaw-node-compile-cache
243- key : ${{ github.repository }}-node-compile-v2 -${{ inputs.node-compile-cache-scope }}-${{ github.event_name == 'pull_request' && format('pr-{0}', github.event.pull_request.number) || ' protected' }} -${{ runner.os }}-${{ runner.arch }}-node-${{ inputs.node-version }}-${{ github.run_id }}-${{ github.run_attempt }}
217+ key : ${{ github.repository }}-node-compile-v3 -${{ inputs.node-compile-cache-scope }}-protected-${{ runner.os }}-${{ runner.arch }}-node-${{ inputs.node-version }}-${{ steps.node-compile-cache-epoch.outputs.value }}
244218 restore-keys : |
245- ${{ github.repository }}-node-compile-v2 -${{ inputs.node-compile-cache-scope }}-${{ github.event_name == 'pull_request' && format('pr-{0}', github.event.pull_request.number) || ' protected' }} -${{ runner.os }}-${{ runner.arch }}-node-${{ inputs.node-version }}-
219+ ${{ github.repository }}-node-compile-v3 -${{ inputs.node-compile-cache-scope }}-protected-${{ runner.os }}-${{ runner.arch }}-node-${{ inputs.node-version }}-
246220
247221 - name : Configure Node compile cache
248222 if : inputs.node-compile-cache == 'true' && runner.os != 'Windows'
249223 env :
250- CACHE_WRITER : ${{ inputs.save-node-compile-cache == 'true' && ((inputs.sticky-disk != 'true' && inputs.runtime-cache-sticky-disk != 'true') || github.event_name != 'pull_request') && '1' || '0' }}
224+ CACHE_WRITER : ${{ inputs.save-node-compile-cache == 'true' && '1' || '0' }}
251225 shell : bash
252226 run : |
253227 set -euo pipefail
0 commit comments