Skip to content

Commit 3d81564

Browse files
schmonzclaude
andcommitted
ci: hard-gate the target self-update e2e (provision two providers)
New isolated `self-update-e2e` job: build a quaude and a naude from an OLD Claude Code, run the `--clode-internal-update` callback, assert the on-disk binary flipped to the NEW version and still PONGs. The acceptance (test/quaude-naude-selfupdate.test.cjs) derives OLD/NEW as the oldest/newest real provider in the clode store and opt-ins on CLODE_PROVIDER_BIN, so this job's job is to put TWO real versions there — CI otherwise has one. It provisions the two newest npm versions (the registry keeps old versions, unlike a rolling CDN, so it won't go stale) via the proven `npm i -g @<ver>` + find-in-npm-root pattern, copying each into a sandbox store. Isolated from node-shim-oracle on purpose: it drives several minutes of real target builds; a slow/red run must not redden that gate. Asserts `skipped 0` — a skipped acceptance is not a pass. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011zrHMKZLSDWYmMsozjXfxL
1 parent f14afd2 commit 3d81564

1 file changed

Lines changed: 71 additions & 0 deletions

File tree

.github/workflows/ci.yml

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -442,3 +442,74 @@ jobs:
442442
echo "provider: $PROV"
443443
export CLODE_PROVIDER_BIN="$PROV"
444444
node --test --test-concurrency=1 $FILES
445+
446+
# HARD GATE for the target self-update callback (2026-07-18): a built target
447+
# (quaude AND naude) rebuilds ITSELF to a newer Claude Code — build from an OLD
448+
# provider, run `--clode-internal-update`, assert the on-disk binary flipped to
449+
# the NEW version and still PONGs. test/quaude-naude-selfupdate.test.cjs opt-ins
450+
# on CLODE_PROVIDER_BIN and derives OLD/NEW as the oldest/newest real provider
451+
# in the clode store, so this job's whole job is to PUT TWO real versions there
452+
# (CI otherwise has one). Isolated from node-shim-oracle on purpose: this drives
453+
# several minutes of real target builds; a slow/red run here must not redden or
454+
# slow that gate. Consumes the CI-tier linux-x64-musl bare engine, same as the
455+
# other oracle jobs.
456+
self-update-e2e:
457+
needs: tjs
458+
if: ${{ !cancelled() }}
459+
runs-on: ubuntu-latest
460+
defaults:
461+
run:
462+
shell: bash
463+
steps:
464+
- uses: actions/checkout@v7
465+
- uses: actions/setup-node@v7
466+
with:
467+
node-version-file: .tool-versions
468+
- uses: actions/download-artifact@v8
469+
with:
470+
name: tjs-linux-x64-musl
471+
path: ${{ runner.temp }}/tjs
472+
- name: Install the runtime dep closure (for the shim + the rebuild)
473+
run: npm ci --prefix deps/claude
474+
- name: Provision postject (deps/clode) so the fused clode-native can assemble a naude
475+
run: npm ci --prefix deps/clode 2>&1 | tail -3
476+
- name: Cache the pinned Node (naude engine — the naude rebuild embeds it)
477+
uses: actions/cache@v4
478+
with:
479+
path: ${{ runner.temp }}/clode-nodes
480+
key: pinned-node-${{ hashFiles('deps/clode/node-pin.json') }}-${{ runner.os }}-${{ runner.arch }}
481+
- name: a target rebuilds itself to a newer Claude Code (self-update e2e, both kinds)
482+
env:
483+
CLODE_TJS: ${{ runner.temp }}/tjs/tjs
484+
CLODE_NODES: ${{ runner.temp }}/clode-nodes
485+
run: |
486+
set -euo pipefail
487+
chmod +x "$CLODE_TJS"
488+
# `build --self` (run by the test's before()) needs a fresh esbuilt bundle.
489+
node scripts/build-clode-main.mjs
490+
# Two real provider versions in a sandbox clode store: the two NEWEST
491+
# published on npm (the registry keeps old versions, unlike a rolling
492+
# release CDN — so this does not go stale). The test bakes the older into
493+
# the initial target and updates to the newer.
494+
STORE="${{ runner.temp }}/selfupd-providers"
495+
VERS=$(npm view @anthropic-ai/claude-code versions --json \
496+
| node -e 'const v=JSON.parse(require("fs").readFileSync(0,"utf8")); process.stdout.write(v.slice(-2).join(" "))')
497+
echo "provisioning two provider versions: $VERS"
498+
# Global install per version (the SAME `npm i -g` + find-in-npm-root
499+
# pattern the windows/node-shim-oracle jobs prove yields a real >20M
500+
# `claude` bin), copying each into the sandbox store before the next
501+
# global install clobbers it. Not a --prefix install (unverified here).
502+
LATEST=""
503+
for V in $VERS; do
504+
npm i -g "@anthropic-ai/claude-code@$V" >/dev/null 2>&1
505+
BIN="$(find "$(npm root -g)/@anthropic-ai/claude-code" -type f -name claude -size +20M 2>/dev/null | head -1)"
506+
if [ -z "$BIN" ]; then echo "ERROR: no claude >20M for $V" >&2; exit 1; fi
507+
mkdir -p "$STORE/$V"; cp "$BIN" "$STORE/$V/claude"; chmod +x "$STORE/$V/claude"
508+
LATEST="$V"
509+
done
510+
echo "store: $STORE (newest = $LATEST)"
511+
# A skipped acceptance is not a pass — assert it actually RAN both cases.
512+
CLODE_PROVIDER_BIN="$STORE/$LATEST/claude" CLODE_PROVIDERS="$STORE" \
513+
node --test --test-timeout=1800000 test/quaude-naude-selfupdate.test.cjs 2>&1 | tee selfupd.out
514+
grep -qE '^(ℹ|#) skipped 0$' selfupd.out \
515+
|| { echo "ERROR: the self-update e2e SKIPPED (or the summary format changed) — the callback went unproven" >&2; exit 1; }

0 commit comments

Comments
 (0)