review: iteration-2 fixes (fragment assertion, evidence paths, hardening)

- build-kernel.sh fragment assertion: survives a missing trailing newline
  (the read footgun, reproduced) and treats an absent symbol on a disable
  line as FATAL, symmetric with the enable arm.
- fetch-kernel-tarball.sh checks the pin before downloading; both fetchers
  add --retry-connrefused.
- mkimage rejects '.'/'..' state keys.
- ui-shot: VM liveness checked before every QMP call, console.log preserved
  as evidence on every failure path, repaint deadline widened to 90s with
  the contended-runner rationale documented.
- rs485-bridge: overflow discards back off one gap and rate-limit their log
  line, mirroring the accept-loop fix; clippy nit fixed.
- .gitignore ignores *.elf/*.map so the untracked artifacts cannot silently
  return; CI shellcheck glob now covers build/ and the rootfs boot scripts
  (directives added for the deliberate in-guest source paths).
- Docs: NPU parity row matches its sibling verification docs; line-pinned
  audit cross-references unpinned; CROSS_COMPILE documented in the build
  header; payload README lists warden-ui; ci-cd tense settled.

Verified: guards negative-tested (bad state keys, no-newline fragment);
boot smoke, portal scenario, ui-shot all PASS; 53 tests green; shellcheck
clean across the widened glob; clippy zero.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018HUayid7W5w7jBdb9Rrj1K
This commit is contained in:
BFE Engineering
2026-08-30 08:34:47 -06:00
co-authored by Claude Fable 5
parent 2756de0b46
commit 973a414f07
17 changed files with 72 additions and 26 deletions
+20 -2
View File
@@ -94,16 +94,29 @@ sys.exit(0 if distinct > 16 else 1)
EOF
}
# The VM can die mid-poll (OOM, crash): check liveness before every QMP
# call so the failure is OUR message + console evidence, not a python
# traceback — and preserve the console log before the trap removes $WORK.
vm_alive_or_die() {
kill -0 "$QEMU_PID" 2>/dev/null && return 0
echo "FATAL: VM exited during the screendump poll" >&2
tail -25 "$WORK/console.log" >&2
mkdir -p "$OUTDIR"; cp "$WORK/console.log" "$OUTDIR/ui-shot-console.log" || true
exit 1
}
# Poll for the first rendered frame (bounded, no guessed sleep).
rendered=0
deadline=$((SECONDS + 90))
while [ $SECONDS -lt $deadline ]; do
vm_alive_or_die
qmp screendump "$WORK/shot1.ppm"
if frame_rendered "$WORK/shot1.ppm"; then rendered=1; break; fi
sleep 3
done
[ "$rendered" = 1 ] || {
echo "FATAL: UI never rendered a non-blank frame within 90s" >&2
mkdir -p "$OUTDIR"; cp "$WORK/console.log" "$OUTDIR/ui-shot-console.log" || true
exit 1
}
@@ -112,9 +125,13 @@ done
# repaint rather than guessing a delay.
qmp tap 16975 1820
changed=0
deadline=$((SECONDS + 30))
# 90s, matching the first-frame budget: TCG repaints are CPU-bound and a
# contended CI runner can be arbitrarily slower than this dev box (same
# margin reasoning as the rs485 test-gap widening).
deadline=$((SECONDS + 90))
while [ $SECONDS -lt $deadline ]; do
sleep 2
vm_alive_or_die
qmp screendump "$WORK/shot2.ppm"
if ! cmp -s "$WORK/shot1.ppm" "$WORK/shot2.ppm"; then changed=1; break; fi
done
@@ -124,7 +141,8 @@ cp "$WORK/shot1.ppm" "$OUTDIR/ui-shot1.ppm"
cp "$WORK/shot2.ppm" "$OUTDIR/ui-shot2.ppm" 2>/dev/null || true
[ "$changed" = 1 ] || {
echo "FATAL: tapping the Metrics tab did not change the frame within 30s — touch is not reaching the UI" >&2
echo "FATAL: tapping the Metrics tab did not change the frame within 90s — touch is not reaching the UI" >&2
cp "$WORK/console.log" "$OUTDIR/ui-shot-console.log" || true
exit 1
}
echo "tap on the Metrics tab repainted the frame (touch reached the UI)"