Skip to content

Commit 518d442

Browse files
robertsLandoclaude
andcommitted
fix: address deep-review findings on docs site branch
- docs: fix broken cross-page anchors in bytecode, recipes, build and sea-mode guides; replace raw /pkg/ prefixed link in index.md with VitePress-managed markdown link. - ci(xcompile): switch cross-compile matrix to workflow_dispatch only (manual trigger is safer and avoids burning macOS/Windows minutes on every PR), wire the node-majors input via a setup job, add timeouts, upload per-cell build logs, short-circuit collate when no results, fix empty-array expansion under bash 3.2 / set -u on macOS runners, add spawnSync timeout, sanitise backticks in PR summary, and drop the dead PR-comment path. - ci(docs): split concurrency so PR builds no longer queue behind production deploys, scope pages/id-token permissions to the deploy job, add timeout-minutes, and add an offline lychee link-check step to catch dead anchors before they ship. - chore(skills): make run-matrix.sh fail fast (set -euo pipefail), write per-cell logs under $WORKDIR/logs so a failing cell is not overwritten, print log paths on stderr, add an unknown-target case, and document the debugging workflow in SKILL.md. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 01770f6 commit 518d442

9 files changed

Lines changed: 220 additions & 94 deletions

File tree

.claude/skills/pkg-xcompile-test/SKILL.md

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,38 @@ GitHub Actions' `macos-13` / `macos-14` runners are the right place for
179179
that; a follow-up CI workflow that runs the hello.js matrix there would
180180
close the last hole.
181181

182+
## Debugging a failing run
183+
184+
Each cell writes its own log; paths are printed on stderr next to any
185+
`FAIL` and re-summarised at the end of the run.
186+
187+
- **Log location**`$PKG_XCOMPILE_WORKDIR/logs/node<major>/build-<mode>-<target>.log`
188+
(and `run-<mode>-<target>.log`). Default workdir is `/tmp/pkg-xcompile`.
189+
Logs are per-cell so a failing build is not overwritten by the next one.
190+
- **Re-run one cell** — the fastest way is still to invoke `pkg` directly
191+
against the same fixture:
192+
```bash
193+
cd /tmp/pkg-xcompile
194+
node /path/to/pkg/lib-es5/bin.js hello.js -t node22-linux-arm64 \
195+
-o /tmp/pkg-xcompile/bin-node22/std-linux-arm64
196+
```
197+
- **`exec format error` on arm64 runs** — binfmt is not registered. After
198+
a reboot `tonistiigi/binfmt` needs to be re-installed:
199+
```bash
200+
docker run --privileged --rm tonistiigi/binfmt --install arm64
201+
```
202+
- **Wine cell always FAIL** — pull the image manually once
203+
(`docker pull scottyhardy/docker-wine`) and inspect
204+
`logs/node<major>/run-sea-win-x64.log` for the actual crash. The
205+
EBADF-stdout gotcha is documented above.
206+
- **SEA FAIL on Node 20** — expected; pkg enforces `host node ≥ 22` for SEA.
207+
- **`Error: UNEXPECTED-20` / silent exit (EXIT=4)** — these are the
208+
tracked Node-22 Standard-mode regressions (issues #181 and #87). Not
209+
environment bugs — see [Node 22 results](#node-22) below.
210+
- **Stale binary hiding a regression** — pkg does not hash its own source
211+
into the output. After rebuilding pkg, delete `bin-node<major>/` before
212+
re-running the matrix.
213+
182214
## The script
183215

184216
The harness lives next to this `SKILL.md` as `run-matrix.sh`. Before

.claude/skills/pkg-xcompile-test/run-matrix.sh

Lines changed: 60 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,15 @@
1313
# the repo stays clean. The tiny hello.js + package.json fixtures are kept
1414
# next to this script and copied into the workdir on first run.
1515
#
16+
# Per-cell logs are written to $PKG_XCOMPILE_WORKDIR/logs/ and their paths
17+
# are printed to stderr next to any FAIL so a failing cell can be inspected
18+
# without re-running the whole matrix.
19+
#
1620
# Builds a tiny hello.js for every {mode,target} combination and runs what
1721
# can be executed on this Linux host (native x64, arm64 via docker+qemu,
1822
# win-x64 via scottyhardy/docker-wine). macOS runtime is skipped (no KVM).
1923

20-
set -u
24+
set -euo pipefail
2125

2226
NODE_MAJOR="${1:-22}"
2327

@@ -28,7 +32,8 @@ REPO_ROOT="$(cd "$SCRIPT_DIR/../../.." && pwd)"
2832
PKG_BIN="${2:-$REPO_ROOT/lib-es5/bin.js}"
2933
WORKDIR="${PKG_XCOMPILE_WORKDIR:-/tmp/pkg-xcompile}"
3034
BINDIR="$WORKDIR/bin-node$NODE_MAJOR"
31-
mkdir -p "$BINDIR"
35+
LOGDIR="$WORKDIR/logs/node$NODE_MAJOR"
36+
mkdir -p "$WORKDIR" "$BINDIR" "$LOGDIR"
3237

3338
if [[ ! -f "$PKG_BIN" ]]; then
3439
echo "pkg not built at $PKG_BIN — run 'yarn build' in $REPO_ROOT first." >&2
@@ -49,7 +54,11 @@ if command -v nvm >/dev/null 2>&1; then
4954
exit 1
5055
}
5156
fi
52-
echo "Host node: $(node -v)"
57+
HOST_NODE_VER="$(node -v)"
58+
echo "Host node: $HOST_NODE_VER" >&2
59+
if [[ "$HOST_NODE_VER" != v${NODE_MAJOR}.* ]]; then
60+
echo "WARN: host node major ($HOST_NODE_VER) != requested ($NODE_MAJOR) — SEA builds may misbehave" >&2
61+
fi
5362

5463
# --- Prepare tiny test project ----------------------------------------------
5564
if [[ ! -f "$WORKDIR/hello.js" ]]; then
@@ -69,61 +78,95 @@ MODES=(std std-public sea)
6978

7079
declare -A RESULT # RESULT[mode/target] = "BUILD / RUN"
7180

81+
# build_one: writes "OK" | "MISSING" | "FAIL" to stdout, progress/log path
82+
# to stderr. Always returns 0 so command substitution never aborts the loop.
7283
build_one() {
7384
local mode="$1" target="$2"
7485
local out="$BINDIR/${mode}-${target}"
7586
[[ "$target" == win-* ]] && out="${out}.exe"
87+
local buildlog="$LOGDIR/build-${mode}-${target}.log"
7688

7789
local args=(hello.js -t "node${NODE_MAJOR}-${target}" -o "$out")
7890
case "$mode" in
7991
sea) args+=(--sea) ;;
8092
std-public) args+=(--public-packages '*' --public) ;;
8193
esac
8294

83-
echo " build: $mode$target"
84-
if (cd "$WORKDIR" && node "$PKG_BIN" "${args[@]}" >/tmp/pkg-build.log 2>&1); then
85-
[[ -f "$out" ]] && echo "OK" || echo "MISSING"
95+
echo " build: $mode$target" >&2
96+
if (cd "$WORKDIR" && node "$PKG_BIN" "${args[@]}" >"$buildlog" 2>&1); then
97+
if [[ -f "$out" ]]; then
98+
echo "OK"
99+
else
100+
echo "MISSING"
101+
echo " log: $buildlog" >&2
102+
fi
86103
else
87104
echo "FAIL"
105+
echo " log: $buildlog" >&2
88106
fi
107+
return 0
89108
}
90109

110+
# run_one: same stdout/stderr contract as build_one.
91111
run_one() {
92112
local mode="$1" target="$2"
93113
local bin="$BINDIR/${mode}-${target}"
94114
[[ "$target" == win-* ]] && bin="${bin}.exe"
95-
[[ ! -f "$bin" ]] && { echo "SKIP-no-bin"; return; }
115+
if [[ ! -f "$bin" ]]; then
116+
echo "SKIP-no-bin"
117+
return 0
118+
fi
119+
local runlog="$LOGDIR/run-${mode}-${target}.log"
96120

97121
case "$target" in
98122
linux-x64)
99-
"$bin" </dev/null >/tmp/pkg-run.log 2>&1 && grep -q "hello from pkg" /tmp/pkg-run.log && echo "OK" || echo "FAIL"
123+
if "$bin" </dev/null >"$runlog" 2>&1 && grep -q "hello from pkg" "$runlog"; then
124+
echo "OK"
125+
else
126+
echo "FAIL"
127+
echo " log: $runlog" >&2
128+
fi
100129
;;
101130
linux-arm64)
102-
docker run --rm --platform linux/arm64 -v "$BINDIR:/mnt" ubuntu:latest \
103-
"/mnt/$(basename "$bin")" </dev/null >/tmp/pkg-run.log 2>&1 \
104-
&& grep -q "hello from pkg" /tmp/pkg-run.log && echo "OK" || echo "FAIL"
131+
if docker run --rm --platform linux/arm64 -v "$BINDIR:/mnt" ubuntu:latest \
132+
"/mnt/$(basename "$bin")" </dev/null >"$runlog" 2>&1 \
133+
&& grep -q "hello from pkg" "$runlog"; then
134+
echo "OK"
135+
else
136+
echo "FAIL"
137+
echo " log: $runlog" >&2
138+
fi
105139
;;
106140
win-x64)
107141
# Wine in non-tty docker breaks Node stdout unless we redirect to a
108142
# file inside the container, then cat it back.
109143
docker run --rm -v "$BINDIR:/mnt" scottyhardy/docker-wine \
110144
bash -c "wine '/mnt/$(basename "$bin")' </dev/null >/tmp/out 2>/tmp/err; cat /tmp/out" \
111-
>/tmp/pkg-run.log 2>/dev/null
112-
grep -q "hello from pkg" /tmp/pkg-run.log && echo "OK" || echo "FAIL"
145+
>"$runlog" 2>/dev/null || true
146+
if grep -q "hello from pkg" "$runlog"; then
147+
echo "OK"
148+
else
149+
echo "FAIL"
150+
echo " log: $runlog" >&2
151+
fi
113152
;;
114153
macos-*)
115154
echo "SKIP-no-mac"
116155
;;
156+
*)
157+
echo "SKIP-unknown"
158+
;;
117159
esac
160+
return 0
118161
}
119162

120163
# --- Execute ----------------------------------------------------------------
121164
echo "=== node $NODE_MAJOR | pkg: $PKG_BIN ==="
122165
for mode in "${MODES[@]}"; do
123166
for target in "${TARGETS[@]}"; do
124-
b=$(build_one "$mode" "$target" | tail -1)
167+
b="$(build_one "$mode" "$target")"
125168
if [[ "$b" == "OK" ]]; then
126-
r=$(run_one "$mode" "$target")
169+
r="$(run_one "$mode" "$target")"
127170
else
128171
r="n/a"
129172
fi
@@ -139,3 +182,5 @@ for target in "${TARGETS[@]}"; do
139182
printf '%-12s | %-18s | %-18s | %-18s\n' "$target" \
140183
"${RESULT[std/$target]}" "${RESULT[std-public/$target]}" "${RESULT[sea/$target]}"
141184
done
185+
186+
printf '\nPer-cell logs: %s\n' "$LOGDIR"

0 commit comments

Comments
 (0)