class v5 kits: the box-side body moved out of the inline command string into tools/class-v5/kits-on-box.sh, run by path from the mirror checkout (main's inline-rm rule of 21:33 BST: no rm, find -delete or truncation inside a bash -c string); kits-remote.sh now only syncs the sources and calls it

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
igneum-labs 2026-10-07 20:37:40 +00:00
parent ce4f0d574a
commit c9af680ddd
2 changed files with 93 additions and 80 deletions

86
tools/class-v5/kits-on-box.sh Executable file
View file

@ -0,0 +1,86 @@
#!/usr/bin/env bash
# The class v5 kit build as it runs ON igneum-build-1 (called by tools/class-v5/kits-remote.sh through the build-server
# library's remote runner, from the worktree's mirror checkout, so this file travels with the commit). A script file by
# path, never an inline string: main's rule of 7 October 2026, 21:33 BST (no rm, find -delete or truncation inside a
# `bash -c` string; tools/ci/inline-rm-check.sh). What it does, in order: the pack loader test with the class v5 cases,
# the Linux and Windows builds of the two one-click workers, the CPU emulation's --check on the class v5 pack, then the
# kit zip at /srv/artefacts/packs/packs-ca3-v5-<stamp>.zip with SHA256SUMS. Logs land in /srv/builds/_log/v5-class/kits-<stamp>.
# bash tools/class-v5/kits-on-box.sh <stamp> <skip-emu 0|1> (cwd = the worktree root on the box)
set -u
STAMP="${1:?stamp}"; SKIP_EMU="${2:-0}"
ZIP="/srv/artefacts/packs/packs-ca3-v5-$STAMP.zip"
LOGDIR="/srv/builds/_log/v5-class/kits-$STAMP"
T=$(mktemp -d /tmp/v5-kits.XXXXXX); S=$T/stage; mkdir -p "$S/bin/linux" "$S/bin/windows" "$S/src" "$S/packs" "$S/tools" "$LOGDIR"
rc=0
step() { echo "STEP $1 $(date -u +%H:%M:%SZ)"; }
fail() { echo "FAIL $1"; rc=1; }
finish() { cp "$T"/*.log "$LOGDIR"/ 2>/dev/null; echo "LOGS $LOGDIR"; rm -rf "$T"; }
V5=proto-cuda/packs-ca3-v5/v5-dn3-epoch0
step packfile-test
cc -std=c99 -Wall -Wextra -Wno-unused-function -O1 -o "$T/packfile-test" proto-cuda/nvrtc/emu/packfile-test.c && "$T/packfile-test" proto-cuda/packs/igneum-devnet-v4-epoch0 "$V5" > "$T/packfile-test.log" 2>&1 || fail "packfile-test ($(tail -1 "$T/packfile-test.log"))"
grep -E '^(FAIL| v5 pack)' "$T/packfile-test.log"; grep -c '^ok' "$T/packfile-test.log" | sed 's/^/packfile-test ok lines /'
step linux-opencl-worker
gcc -std=c99 -O2 -Wall -Wextra -Wno-stringop-truncation -Wno-format-truncation -DIGNEUM_CL_DYNAMIC -DCL_TARGET_OPENCL_VERSION=120 -I proto-cuda/packs/igneum-devnet-v4-epoch0 -DIGNEUM_KERNEL_PATH='"kernel_bound.cl"' -o "$S/bin/linux/igneum-worker-opencl" proto-opencl/host.c -ldl -lpthread 2> "$T/cl-linux.log" || { fail "linux opencl worker"; head -20 "$T/cl-linux.log"; }
step linux-cuda-worker
g++ -std=c++17 -O2 -Wall -Wextra -I proto-cuda/nvrtc -I /usr/local/cuda/include -o "$S/bin/linux/igneum-worker-cuda" proto-cuda/nvrtc/worker.cpp -ldl -lpthread 2> "$T/cuda-linux.log" || { fail "linux cuda worker"; head -20 "$T/cuda-linux.log"; }
step windows-cuda-worker
x86_64-w64-mingw32-g++ -std=c++17 -O2 -Wall -Wextra -static -I proto-cuda/nvrtc -I /usr/local/cuda/include -o "$S/bin/windows/igneum-worker-cuda.exe" proto-cuda/nvrtc/worker.cpp 2> "$T/cuda-win.log" && x86_64-w64-mingw32-strip "$S/bin/windows/igneum-worker-cuda.exe" || { fail "windows cuda worker"; head -20 "$T/cuda-win.log"; }
step windows-opencl-worker
# the Khronos CL headers alone (never -I /usr/include: that puts glibc's stdint.h ahead of mingw's)
mkdir -p "$T/inc" && cp -r /usr/include/CL "$T/inc/"
x86_64-w64-mingw32-gcc -std=c99 -O2 -Wall -Wextra -Wno-stringop-truncation -Wno-format-truncation -static -DIGNEUM_CL_DYNAMIC -DCL_TARGET_OPENCL_VERSION=120 -I "$T/inc" -I proto-cuda/packs/igneum-devnet-v4-epoch0 -DIGNEUM_KERNEL_PATH='"kernel_bound.cl"' -o "$S/bin/windows/igneum-worker-opencl.exe" proto-opencl/host.c 2> "$T/cl-win.log" && x86_64-w64-mingw32-strip "$S/bin/windows/igneum-worker-opencl.exe" || { fail "windows opencl worker"; head -20 "$T/cl-win.log"; }
if [ "$SKIP_EMU" = 0 ]; then
step emu-check-v5
# the CPU emulation (proto-cuda/nvrtc/emu/test.sh's build) with pack A = the class v5 pack and pack B = the v4 control
E=$T/emu; mkdir -p "$E"
emu_kernel() { { echo '#include <cuda_runtime.h>'; echo '#include <cstdint>'; echo "namespace $2 {"; sed -E 's/([A-Za-z_0-9]+)<<<([^,]+), ([^>]+)>>>\(/emu_launch(\1, \2, \3, /' "$1/$3.cu"; echo "}"; } > "$E/$3_$2.cpp"; g++ -std=c++17 -O2 -w -I proto-cuda/emu -I "$1" -c "$E/$3_$2.cpp" -o "$E/$3_$2.o"; }
emu_kernel "$V5" emu_pack_a kernel && emu_kernel "$V5" emu_pack_a kernel_bound && emu_kernel proto-cuda/packs-ca3-v5/v4-genesis emu_pack_b kernel && emu_kernel proto-cuda/packs-ca3-v5/v4-genesis emu_pack_b kernel_bound \
&& g++ -std=c++17 -O2 -Wall -Wextra -DIGNEUM_EMU -I proto-cuda/nvrtc -I /usr/local/cuda/include -c proto-cuda/nvrtc/worker.cpp -o "$E/worker.o" \
&& g++ -std=c++17 -O2 -Wall -Wextra -DIGNEUM_EMU -DIGNEUM_EMU_TWO_PACKS -I proto-cuda/nvrtc -I proto-cuda/emu -I /usr/local/cuda/include -c proto-cuda/nvrtc/emu/emu_backend.cpp -o "$E/emu_backend.o" \
&& g++ -std=c++17 -O2 -w -I proto-cuda/emu -c proto-cuda/emu/shim.cpp -o "$E/shim.o" \
&& g++ -o "$E/igneum-worker-cuda-emu" "$E"/*.o -pthread 2> "$T/emu-build.log" || { fail "emu build"; head -30 "$T/emu-build.log"; }
if [ -x "$E/igneum-worker-cuda-emu" ]; then
( IGNEUM_EMU_PACK="$PWD/$V5" IGNEUM_EMU_PACK2="$PWD/proto-cuda/packs-ca3-v5/v4-genesis" timeout 1500 nice -n 10 "$E/igneum-worker-cuda-emu" --check --pack "$V5" > "$T/emu-check.log" 2>&1 ) || fail "emu --check on the class v5 pack (rc $?)"
grep -E '^check PASS|self-test|FAIL|error' "$T/emu-check.log" | cut -c1-400
fi
fi
if [ "$rc" != 0 ]; then echo "KIT not written: a step failed (rc $rc)"; finish; exit 1; fi
step stage
for p in v4-genesis v5-genesis v5-dn3-epoch0; do mkdir -p "$S/packs/$p"; cp proto-cuda/packs-ca3-v5/$p/* "$S/packs/$p/"; done
cp proto-cuda/nvrtc/worker.cpp proto-cuda/nvrtc/packfile.h proto-cuda/nvrtc/cuda_api.h proto-opencl/host.c proto-opencl/cl_dynamic.h proto-newpow/class-v5/bench.cu proto-newpow/class-v5/run.sh proto-metal/packbench.swift "$S/src/"
cp tools/class-v5/fleet-cuda-v5-bench.sh tools/class-v5/pc1-amd-v5-bench.ps1 "$S/tools/"
cat > "$S/README.txt" <<'R'
packs-ca3-v5: the class v5 kit (Igneum, 7 October 2026; docs/design/class-v5-stored-state.md)
packs/v5-dn3-epoch0 the first class v5 pack: Devnet 3 epoch 0, program id e5a4ac5978462156, 11 state leaves (leaves.bin, 704 B) under
state root 7e37a9fb19b154d32daf5bf30a50d339a75029fbc9eec9ea20e95439dba5a311, cache FNV-1a 64 7334fa46e5d972eb
expected fingerprint of the 2^24 outputs at base nonce 0: 82b19cbde8557ea5 (Metal, M5 Max, 18:07:09Z) on every platform
packs/v5-genesis the string-seed class v5 pack over the devnet's 93 leaves; packs/v4-genesis the class v4 control (sub-version 3)
bin/linux igneum-worker-cuda (NVRTC, libcuda + libnvrtc.so.12 at run time), igneum-worker-opencl (libOpenCL.so.1 at run time)
bin/windows igneum-worker-cuda.exe (nvcuda.dll + nvrtc64 at run time), igneum-worker-opencl.exe (OpenCL.dll at run time)
Every worker reads a class v5 pack's leaves.bin, checks it against the pack's IGNEUM_STATE_LEAVES_FNV64, uploads it for igneum_build and
frees it after the build; a pack without its leaves builds nothing. Self-test: cache head, last line and FNV; dataset head, last word and
64 samples; 96 vector lanes. Bench: igneum-worker-cuda --bench --pack packs/v5-dn3-epoch0 --batch-log2 24 (fleet-cuda-v5-bench.sh);
igneum-worker-opencl --bench-pack --pack packs/v5-dn3-epoch0 --batch-log2 24 --device <n> (pc1-amd-v5-bench.ps1); src/bench.cu with nvcc.
Intel: not measured tonight (7 October 2026); no Arc B580 sits on PC 1 or PC 2 and the only Arc path needs a driver click, which no PC job
may raise; the card's holder and a click-free driver path are owed. The OpenCL worker takes the Intel device by index the same way.
R
( cd "$S" && find . -type f ! -name SHA256SUMS | sort | xargs sha256sum > SHA256SUMS )
mkdir -p /srv/artefacts/packs
python3 - "$S" "$ZIP" <<'PY'
import os, sys, zipfile
stage, out = sys.argv[1], sys.argv[2]
with zipfile.ZipFile(out, 'w', zipfile.ZIP_DEFLATED) as z:
for dp, dn, fn in os.walk(stage):
dn.sort()
for f in sorted(fn):
p = os.path.join(dp, f); rel = os.path.relpath(p, stage)
zi = zipfile.ZipInfo(rel, date_time=(2026, 10, 7, 0, 0, 0)); zi.compress_type = zipfile.ZIP_DEFLATED
zi.external_attr = (0o755 if rel.startswith('bin/') or rel.endswith('.sh') else 0o644) << 16
with open(p, 'rb') as fh: z.writestr(zi, fh.read())
PY
sha256sum "$ZIP" | cut -c1-64 > "$ZIP.sha256"
echo "KIT $ZIP bytes $(stat -c %s "$ZIP") files $(python3 -c "import zipfile,sys; print(len(zipfile.ZipFile(sys.argv[1]).namelist()))" "$ZIP")"
echo "KIT sha256 $(cat "$ZIP.sha256")"
for b in "$S"/bin/linux/* "$S"/bin/windows/*; do echo "BIN $(basename "$(dirname "$b")")/$(basename "$b") $(stat -c %s "$b") bytes sha256 $(sha256sum "$b" | cut -c1-64)"; done
finish
exit 0

View file

@ -12,7 +12,10 @@
# IGNEUM_AGENT=v5-kits tools/class-v5/kits-remote.sh [--box 1] [--skip-emu]
#
# Takes one of the box's build slots through infra/build-server/remote-run.sh (bs_remote_run), box 1 by default (the
# build-server lane's word of 7 October 2026, 19:4x BST: the kit builds on build-1 explicitly).
# build-server lane's word of 7 October 2026, 19:4x BST: the kit builds on build-1 explicitly). The work itself is
# tools/class-v5/kits-on-box.sh, a script file run by path on the box (the inline-rm rule of 21:33 BST); when the
# build-server lane's lease tool is in place, the same file goes through `/srv/builds/_bin/lease pool <threads> -- bash
# tools/class-v5/kits-on-box.sh ...` with the label "v5 kit".
set -euo pipefail
HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
BS_TOOL=class-v5-kits
@ -31,85 +34,9 @@ ZIP="/srv/artefacts/packs/packs-ca3-v5-$STAMP.zip"
bs_toolchain_check
bs_sync_sources
bs_log "sources at $WT (commit $BS_SHA on $BS_BRANCH); building the class v5 kits on box $BOX"
read -r -d '' CMD <<EOF2 || true
set -u
cd '$WT'
T=\$(mktemp -d /tmp/v5-kits.XXXXXX); S=\$T/stage; mkdir -p \$S/bin/linux \$S/bin/windows \$S/src \$S/packs \$S/tools
rc=0
step() { echo "STEP \$1 \$(date -u +%H:%M:%SZ)"; }
fail() { echo "FAIL \$1"; rc=1; }
V5=proto-cuda/packs-ca3-v5/v5-dn3-epoch0
step packfile-test
cc -std=c99 -Wall -Wextra -Wno-unused-function -O1 -o \$T/packfile-test proto-cuda/nvrtc/emu/packfile-test.c && \$T/packfile-test proto-cuda/packs/igneum-devnet-v4-epoch0 \$V5 > \$T/packfile-test.log 2>&1 || fail "packfile-test (\$(tail -1 \$T/packfile-test.log))"
grep -E '^(FAIL| v5 pack)' \$T/packfile-test.log; grep -c '^ok' \$T/packfile-test.log | sed 's/^/packfile-test ok lines /'
step linux-opencl-worker
gcc -std=c99 -O2 -Wall -Wextra -Wno-stringop-truncation -Wno-format-truncation -DIGNEUM_CL_DYNAMIC -DCL_TARGET_OPENCL_VERSION=120 -I proto-cuda/packs/igneum-devnet-v4-epoch0 -DIGNEUM_KERNEL_PATH='"kernel_bound.cl"' -o \$S/bin/linux/igneum-worker-opencl proto-opencl/host.c -ldl -lpthread 2> \$T/cl-linux.log || { fail "linux opencl worker"; head -20 \$T/cl-linux.log; }
step linux-cuda-worker
g++ -std=c++17 -O2 -Wall -Wextra -I proto-cuda/nvrtc -I /usr/local/cuda/include -o \$S/bin/linux/igneum-worker-cuda proto-cuda/nvrtc/worker.cpp -ldl -lpthread 2> \$T/cuda-linux.log || { fail "linux cuda worker"; head -20 \$T/cuda-linux.log; }
step windows-cuda-worker
x86_64-w64-mingw32-g++ -std=c++17 -O2 -Wall -Wextra -static -I proto-cuda/nvrtc -I /usr/local/cuda/include -o \$S/bin/windows/igneum-worker-cuda.exe proto-cuda/nvrtc/worker.cpp 2> \$T/cuda-win.log && x86_64-w64-mingw32-strip \$S/bin/windows/igneum-worker-cuda.exe || { fail "windows cuda worker"; head -20 \$T/cuda-win.log; }
step windows-opencl-worker
# the Khronos CL headers alone (never -I /usr/include: that puts glibc's stdint.h ahead of mingw's)
mkdir -p \$T/inc && cp -r /usr/include/CL \$T/inc/
x86_64-w64-mingw32-gcc -std=c99 -O2 -Wall -Wextra -Wno-stringop-truncation -Wno-format-truncation -static -DIGNEUM_CL_DYNAMIC -DCL_TARGET_OPENCL_VERSION=120 -I \$T/inc -I proto-cuda/packs/igneum-devnet-v4-epoch0 -DIGNEUM_KERNEL_PATH='"kernel_bound.cl"' -o \$S/bin/windows/igneum-worker-opencl.exe proto-opencl/host.c 2> \$T/cl-win.log && x86_64-w64-mingw32-strip \$S/bin/windows/igneum-worker-opencl.exe || { fail "windows opencl worker"; head -20 \$T/cl-win.log; }
if [ $SKIP_EMU = 0 ]; then
step emu-check-v5
# the CPU emulation (proto-cuda/nvrtc/emu/test.sh's build) with pack A = the class v5 pack and pack B = the v4 control
E=\$T/emu; mkdir -p \$E
emu_kernel() { { echo '#include <cuda_runtime.h>'; echo '#include <cstdint>'; echo "namespace \$2 {"; sed -E 's/([A-Za-z_0-9]+)<<<([^,]+), ([^>]+)>>>\\(/emu_launch(\\1, \\2, \\3, /' "\$1/\$3.cu"; echo "}"; } > "\$E/\$3_\$2.cpp"; g++ -std=c++17 -O2 -w -I proto-cuda/emu -I "\$1" -c "\$E/\$3_\$2.cpp" -o "\$E/\$3_\$2.o"; }
emu_kernel \$V5 emu_pack_a kernel && emu_kernel \$V5 emu_pack_a kernel_bound && emu_kernel proto-cuda/packs-ca3-v5/v4-genesis emu_pack_b kernel && emu_kernel proto-cuda/packs-ca3-v5/v4-genesis emu_pack_b kernel_bound \\
&& g++ -std=c++17 -O2 -Wall -Wextra -DIGNEUM_EMU -I proto-cuda/nvrtc -I /usr/local/cuda/include -c proto-cuda/nvrtc/worker.cpp -o \$E/worker.o \\
&& g++ -std=c++17 -O2 -Wall -Wextra -DIGNEUM_EMU -DIGNEUM_EMU_TWO_PACKS -I proto-cuda/nvrtc -I proto-cuda/emu -I /usr/local/cuda/include -c proto-cuda/nvrtc/emu/emu_backend.cpp -o \$E/emu_backend.o \\
&& g++ -std=c++17 -O2 -w -I proto-cuda/emu -c proto-cuda/emu/shim.cpp -o \$E/shim.o \\
&& g++ -o \$E/igneum-worker-cuda-emu \$E/*.o -pthread 2> \$T/emu-build.log || { fail "emu build"; head -30 \$T/emu-build.log; }
if [ -x \$E/igneum-worker-cuda-emu ]; then
( IGNEUM_EMU_PACK=\$PWD/\$V5 IGNEUM_EMU_PACK2=\$PWD/proto-cuda/packs-ca3-v5/v4-genesis timeout 1500 nice -n 10 \$E/igneum-worker-cuda-emu --check --pack \$V5 > \$T/emu-check.log 2>&1 ) || fail "emu --check on the class v5 pack (rc \$?)"
grep -E '^check PASS|self-test|FAIL|error' \$T/emu-check.log | cut -c1-400
fi
fi
if [ \$rc != 0 ]; then echo "KIT not written: a step failed (rc \$rc)"; mkdir -p /srv/builds/_log/v5-class/kits-$STAMP && cp \$T/*.log /srv/builds/_log/v5-class/kits-$STAMP/; echo "LOGS /srv/builds/_log/v5-class/kits-$STAMP"; rm -rf \$T; exit 1; fi
step stage
for p in v4-genesis v5-genesis v5-dn3-epoch0; do mkdir -p \$S/packs/\$p; cp proto-cuda/packs-ca3-v5/\$p/* \$S/packs/\$p/; done
cp proto-cuda/nvrtc/worker.cpp proto-cuda/nvrtc/packfile.h proto-cuda/nvrtc/cuda_api.h proto-opencl/host.c proto-opencl/cl_dynamic.h proto-newpow/class-v5/bench.cu proto-newpow/class-v5/run.sh proto-metal/packbench.swift \$S/src/
cp tools/class-v5/fleet-cuda-v5-bench.sh tools/class-v5/pc1-amd-v5-bench.ps1 \$S/tools/
cat > \$S/README.txt <<'R'
packs-ca3-v5: the class v5 kit (Igneum, 7 October 2026; docs/design/class-v5-stored-state.md)
packs/v5-dn3-epoch0 the first class v5 pack: Devnet 3 epoch 0, program id e5a4ac5978462156, 11 state leaves (leaves.bin, 704 B) under
state root 7e37a9fb19b154d32daf5bf30a50d339a75029fbc9eec9ea20e95439dba5a311, cache FNV-1a 64 7334fa46e5d972eb
expected fingerprint of the 2^24 outputs at base nonce 0: 82b19cbde8557ea5 (Metal, M5 Max, 18:07:09Z) on every platform
packs/v5-genesis the string-seed class v5 pack over the devnet's 93 leaves; packs/v4-genesis the class v4 control (sub-version 3)
bin/linux igneum-worker-cuda (NVRTC, libcuda + libnvrtc.so.12 at run time), igneum-worker-opencl (libOpenCL.so.1 at run time)
bin/windows igneum-worker-cuda.exe (nvcuda.dll + nvrtc64 at run time), igneum-worker-opencl.exe (OpenCL.dll at run time)
Every worker reads a class v5 pack's leaves.bin, checks it against the pack's IGNEUM_STATE_LEAVES_FNV64, uploads it for igneum_build and
frees it after the build; a pack without its leaves builds nothing. Self-test: cache head, last line and FNV; dataset head, last word and
64 samples; 96 vector lanes. Bench: igneum-worker-cuda --bench --pack packs/v5-dn3-epoch0 --batch-log2 24 (fleet-cuda-v5-bench.sh);
igneum-worker-opencl --bench-pack --pack packs/v5-dn3-epoch0 --batch-log2 24 --device <n> (pc1-amd-v5-bench.ps1); src/bench.cu with nvcc.
Intel: not measured tonight (7 October 2026); no Arc B580 sits on PC 1 or PC 2 and the only Arc path needs a driver click, which no PC job
may raise; the card's holder and a click-free driver path are owed. The OpenCL worker takes the Intel device by index the same way.
R
( cd \$S && find . -type f ! -name SHA256SUMS | sort | xargs sha256sum > SHA256SUMS )
mkdir -p /srv/artefacts/packs
python3 - "\$S" '$ZIP' <<'PY'
import os, sys, zipfile
stage, out = sys.argv[1], sys.argv[2]
with zipfile.ZipFile(out, 'w', zipfile.ZIP_DEFLATED) as z:
for dp, dn, fn in os.walk(stage):
dn.sort()
for f in sorted(fn):
p = os.path.join(dp, f); rel = os.path.relpath(p, stage)
zi = zipfile.ZipInfo(rel, date_time=(2026, 10, 7, 0, 0, 0)); zi.compress_type = zipfile.ZIP_DEFLATED
zi.external_attr = (0o755 if rel.startswith('bin/') or rel.endswith('.sh') else 0o644) << 16
with open(p, 'rb') as fh: z.writestr(zi, fh.read())
PY
sha256sum '$ZIP' | cut -c1-64 > '$ZIP.sha256'
echo "KIT $ZIP bytes \$(stat -c %s '$ZIP') files \$(python3 -c "import zipfile,sys; print(len(zipfile.ZipFile(sys.argv[1]).namelist()))" '$ZIP')"
echo "KIT sha256 \$(cat '$ZIP.sha256')"
for b in \$S/bin/linux/* \$S/bin/windows/*; do echo "BIN \$(basename \$(dirname \$b))/\$(basename \$b) \$(stat -c %s \$b) bytes sha256 \$(sha256sum \$b | cut -c1-64)"; done
cp \$T/*.log /srv/builds/_log/v5-class/kits-$STAMP/ 2>/dev/null || { mkdir -p /srv/builds/_log/v5-class/kits-$STAMP && cp \$T/*.log /srv/builds/_log/v5-class/kits-$STAMP/; }
echo "LOGS /srv/builds/_log/v5-class/kits-$STAMP"
rm -rf \$T
( exit \$rc )
EOF2
# the body runs from a script FILE at the worktree's mirror checkout (tools/class-v5/kits-on-box.sh, carried by the commit), never
# an inline string: main's rule of 7 October 2026, 21:33 BST (no rm, find -delete or truncation inside a bash -c string)
CMD="cd '$WT' && bash tools/class-v5/kits-on-box.sh '$STAMP' '$SKIP_EMU'"
set +e
BR_KIND=build BR_COMMAND="class v5 kits (packfile-test, emu --check v5, Linux and Windows workers, kit zip)" BR_TARGET="x86_64-linux+windows" BR_ARTEFACTS="" \
bs_remote_run "$WT" "$BS_WT class-v5 kits" "$CMD" 2>&1 | tee "/tmp/v5-kits-$STAMP.log" | grep -E '^(STEP|FAIL|KIT|BIN|LOGS|check PASS|self-test|packfile-test|emu:| v5|build-remote: RESULT)'