Skip to content

Commit f57066d

Browse files
committed
docs(console-pin): the injection gate's header and remedy, and release.yml's key comment, say the two dist keys now differ (#20765)
ci.yml's console dist key hashes a superset of release.yml's since the previous commit, so three pieces of prose went false: the header of scripts/check-console-injection.mjs restated the old key and said packages/spec was out of the console filter, its remedy() fallback printed that key as the one to delete, and release.yml asked the two keys to stay in step. The header and the fallback now point at each workflow's restore step instead of carrying a third copy of the key, and release.yml's comment says its narrower key is deliberate. No key, step or env changes. Claude-Session: https://claude.ai/code/session_017VaLJnYwhPsanVCe9dMCJU Co-authored-by: Claude <noreply@anthropic.com>
1 parent 13612da commit f57066d

3 files changed

Lines changed: 51 additions & 27 deletions

File tree

‎.github/workflows/ci.yml‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2438,8 +2438,8 @@ jobs:
24382438
#
24392439
# ⚠️ release.yml's restore step still keys on the pin and the build script
24402440
# alone, so the two workflows no longer share dist entries: each builds its
2441-
# own on a miss. That file's comment asks for the two to stay in step; which
2442-
# way to reconcile them is recorded on #20765.
2441+
# own on a miss. The narrower release key is deliberate, and that file's
2442+
# comment says why (#20765).
24432443
#
24442444
# Split restore/save where release.yml uses the combined action, because the
24452445
# combined form's post-step saves even when the job FAILED. build-console.sh

‎.github/workflows/release.yml‎

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1378,9 +1378,13 @@ jobs:
13781378
- name: Build
13791379
run: pnpm run build
13801380

1381-
# ci.yml's Console Pin Gate (#4290) uses this exact key, so the pin bump's
1382-
# PR run and this job share one build — keep the two in step if either
1383-
# input set changes.
1381+
# This key hashes the pin and the build script. ci.yml's Console Pin Gate
1382+
# (#4290) hashes a SUPERSET: those two, the probe scripts and the spec's
1383+
# entry layout (#20765). So the two workflows no longer share dist entries,
1384+
# and each one builds its own on a miss. Keeping this key narrower is
1385+
# deliberate. Following ci.yml would rebuild the console on every Version
1386+
# Packages merge, and publishing a cached console whose spec content lags
1387+
# is the existing cache design.
13841388
#
13851389
# Split restore/save, matching ci.yml, and not the combined actions/cache
13861390
# action: the combined form's post-step saves even when the job FAILED,

‎scripts/check-console-injection.mjs‎

Lines changed: 42 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -7,20 +7,23 @@
77
*
88
* ## The hole this closes (objectstack#9667)
99
*
10-
* The vendored Console SPA is cached under
11-
*
12-
* ${{ runner.os }}-console-dist-${{ hashFiles('.objectui-sha', 'scripts/build-console.sh') }}
13-
*
14-
* spelled identically in ci.yml (twice: restore + save) and release.yml. The key
15-
* does NOT include packages/spec, so a dist built while spec was at state X is
16-
* restored and reused after spec moves on — and because
10+
* The vendored Console SPA is cached under a key each workflow spells in its
11+
* own restore step: ci.yml's `console-pin` job and release.yml's publish job.
12+
* The key is deliberately not restated here, because a copy in a comment is one
13+
* that nothing holds in step (scripts/check-ci-filter-parity.mjs holds ci.yml's
14+
* spellings to its `console` filter). The two keys no longer match
15+
* (objectstack#20765): release.yml hashes the pin and the build script, and
16+
* ci.yml hashes those plus the probe scripts and the spec's ENTRY LAYOUT
17+
* (package.json, tsup.config.ts). Neither includes the spec's CONTENT, so a dist
18+
* built while spec was at state X is restored and reused after spec moves on,
19+
* and because
1720
* scripts/assert-console-spec-injection.mjs runs INSIDE build-console.sh, a
1821
* cache hit skips the entire build step and therefore skips the assertion too.
1922
* The injection fixed resolution; the cache could still serve a console whose
2023
* bundled spec is not the one this build proved.
2124
*
22-
* Adding packages/spec to the cache key was considered and REJECTED: it busts
23-
* the key on every spec change and forces a full cold console rebuild (~20 min,
25+
* Adding the whole of packages/spec to the cache key was considered and
26+
* REJECTED: it busts the key on every spec change and forces a full cold console rebuild (~20 min,
2427
* measured) on a repo doing ~18 merges a day. The cache's economics — including
2528
* ci.yml's deliberate split restore/save, which exists so a failed build never
2629
* poisons the entry — are kept exactly as they are. Only the silent half is
@@ -48,21 +51,27 @@
4851
* the stamped detector is STILL ABSENT from this tree's spec. Once the published
4952
* spec catches up, the stamp is expired and says so instead of passing.
5053
*
51-
* ## Why packages/spec is NOT in ci.yml's console filter (objectstack#9710)
54+
* ## Why the rest of packages/spec is NOT in ci.yml's console filter (objectstack#9710)
5255
*
53-
* That filter lists the pin, the build script and this gate's own sources — not
54-
* packages/spec — so a spec-only PR never schedules Console Pin Gate and never
55-
* reaches this check. Adding it is the obvious next thought; it was measured and
56+
* That filter lists the pin, the build and probe scripts and this gate's own
57+
* sources, and since objectstack#20765 also the spec's ENTRY LAYOUT
58+
* (package.json's exports map and tsup.config.ts). ci.yml's dist key hashes
59+
* each of those build inputs too, so a head that moves the entry layout MISSES
60+
* the cache, rebuilds, and assert-console-spec-injection.mjs judges it; a
61+
* cache hit could not have, as the paragraphs below explain. The rest of
62+
* packages/spec is its CONTENT, which is in neither the filter nor the key, so
63+
* a content-only spec PR never schedules Console Pin Gate and never reaches
64+
* this check. Adding the content is the obvious next thought; it was measured and
5665
* DECLINED, and the reason is not cost, which is why it is recorded here rather
5766
* than left on a card: the job it would schedule is vacuous, not expensive.
5867
*
5968
* Count what this gate can fail on. Of its six failure verdicts, FIVE are pure
6069
* functions of the RESTORED DIST and its stamp — a missing dist, unreadable
6170
* assets or a malformed stamp, a missing stamp, the published-only detector
6271
* present in the bundle, the stamp's own fresh witness missing from it. A
63-
* spec-only diff cannot move any of those: the cache key is the one spelled at
64-
* the top of this header — the pin and the build script, nothing else — and
65-
* entries under it are IMMUTABLE, so all five replay what the last
72+
* content-only spec diff cannot move any of those: it does not move the cache
73+
* key (see the top of this header for what each key hashes), and entries under
74+
* a key are IMMUTABLE, so all five replay what the last
6675
* console-filtered run already saw. Exactly ONE verdict reads this tree, the
6776
* expiry re-check, and it needs packages/spec/dist because readSpecBlob resolves
6877
* the package's exports map. So the restore-only job proposed there — no
@@ -214,13 +223,17 @@ const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
214223
* How an operator clears a cached dist this gate refused.
215224
*
216225
* ⛔ The `gh cache delete` line is MAINTAINER-ONLY — it needs repo write scope,
217-
* and it deletes an entry shared by ci.yml and release.yml. It is named anyway
218-
* because ruling out a remedy an operator cannot discover is how a red becomes
219-
* noise; a contributor who cannot run it should hand this message to a
220-
* maintainer rather than guess.
226+
* and it deletes an entry every later run of that workflow under the same key
227+
* would restore. It is named anyway because ruling out a remedy an operator
228+
* cannot discover is how a red becomes noise; a contributor who cannot run it
229+
* should hand this message to a maintainer rather than guess.
230+
*
231+
* The key comes from the CI step (`CONSOLE_DIST_CACHE_KEY`). Without it (a local
232+
* run) the line names WHERE each workflow spells its key instead of restating
233+
* one: ci.yml's and release.yml's keys differ (objectstack#20765), and a copy
234+
* here would be a third spelling nothing holds in step.
221235
*/
222236
function remedy(cacheKey) {
223-
const key = cacheKey || '${{ runner.os }}-console-dist-${{ hashFiles(\'.objectui-sha\', \'scripts/build-console.sh\') }}';
224237
return [
225238
' How to clear this:',
226239
'',
@@ -231,7 +244,14 @@ function remedy(cacheKey) {
231244
' • In CI — the restored artifact is a CACHE ENTRY, not anything in this PR.',
232245
" Nothing in the diff can fix it; the entry has to go. ⛔ MAINTAINER-ONLY:",
233246
'',
234-
` gh cache delete "${key}"`,
247+
` gh cache delete "${cacheKey || 'KEY'}"`,
248+
...(cacheKey
249+
? []
250+
: [
251+
'',
252+
" KEY is the key the failing job's restore step printed. ci.yml's",
253+
" `console-pin` job and release.yml's publish job each spell their own.",
254+
]),
235255
'',
236256
' then re-run the Console Pin Gate job. The next run misses, rebuilds,',
237257
' and re-stamps.',

0 commit comments

Comments
 (0)