From c11157f13752878889126cbd4515dc7bbaa6afde Mon Sep 17 00:00:00 2001 From: vk Date: Tue, 1 Sep 2026 17:13:32 +0530 Subject: [PATCH 1/2] Provision python3 in the container matrix, unblock the pre-tag carve-out, and make check 61 say what failed MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Three defects, all shipped in v1.61.0, all found by CI on the first commit where the pre-tag red was not masking them. CONTAINER MATRIX, check 63's skip. tests/container-matrix.sh installs bash git jq curl ca-certificates shellcheck and never python3, so check 63 was guaranteed to skip in every image. The skip classifier accepts a reason only if it matches 'plugin manifest|authenticat|claude CLI', so all three lanes failed on the classification -- debian's gate printed VERIFIED and the lane still failed, which is the classifier working. Adding "python3 not on PATH" to that keyword list would have been a lie about what the skip is, and laundering a skip under a credentials explanation is the exact regression tests/container-skip-classify.sh's PROOF 4 was added to stop. Provision the tool instead. CONTAINER MATRIX, the carve-out that could never fire. bin/doctor:1292 prints `DRIFT ✖` as its generic summary whenever the fail count is non-zero. It name-collides with a real drift banner and carries no diagnostic content. The carve-out stripped the allowed finding's own line but not that one, so with "declared release is fetchable" as the SOLE failure the residual was still non-empty and every image reported `doctor exit=1; DRIFT ✖`. The carve-out I shipped yesterday was unreachable by construction. Row 62b proved the list and the doctor branch; nothing proved the filter against real output, which is the third time in this repository that the two halves were each tested and the join was not. Dropping the banner softens nothing -- every individual finding prints its own ✖ -- but the banner was accidentally acting as a guard, so the guard it was standing in for is now explicit: the allowed finding must actually appear in the output, or a doctor that fails while printing no findings would pass. Debian passing while alpine and ubuntu failed was not an OS difference. Debian ran at 10:48 with the tag still on origin; alpine and ubuntu at 10:50 and 10:53, after cleanup-on-failed-gate removed it. A live-network race across a seven-minute matrix, both dash images on opposite sides. CHECK 61 on Alpine. It goes red there and nowhere else, and reported only "vstack trust failed" because the command ran with `>/dev/null 2>&1`. A check that knows something is wrong and has discarded the only sentence saying what. Two reproduction attempts against a byte-identical image could not make it fail, which is precisely when the swallowed stderr is the whole investigation. It now keeps rc and stderr and puts both in the failure body. This commit does not claim to fix that defect; it makes the next red report it. Co-Authored-By: Claude Opus 5 (1M context) --- .claude/verify.sh | 24 +++++++++++++++++++----- tests/container-matrix.sh | 20 +++++++++++++++----- 2 files changed, 34 insertions(+), 10 deletions(-) diff --git a/.claude/verify.sh b/.claude/verify.sh index 9351158..ea22db3 100755 --- a/.claude/verify.sh +++ b/.claude/verify.sh @@ -4440,7 +4440,19 @@ c61_mkrepo(){ # chmod +x "$1/.claude/verify.sh" } c61_store(){ printf '%s' "$1/home/.config/agents/verify-trust"; } -c61_trust(){ HOME="$1/home" ./bin/vstack trust "$1" --yes >/dev/null 2>&1; } +# Keeps stderr and the exit code instead of discarding them. This check went red on Alpine in CI +# and nowhere else, and all three lanes reported only "vstack trust failed" because the command +# was run with `>/dev/null 2>&1` -- a check that knows something is wrong and has thrown away the +# only sentence saying what. Two reproduction attempts against a byte-identical image failed to +# make it fail, which is exactly the case where the swallowed stderr is the whole investigation. +c61_last="" +c61_trust(){ + c61_last=$(HOME="$1/home" ./bin/vstack trust "$1" --yes 2>&1 >/dev/null) + c61_rc=$? + [ -n "$c61_last" ] || c61_last="(command printed nothing on stderr)" + c61_last="rc=$c61_rc, stderr: $(printf '%s' "$c61_last" | tr '\n' ' ')" + return "$c61_rc" +} # Lane 2 -- positive control. A repo whose gate runs ./scripts/ci.sh must get ci.sh recorded, and # that path is in no hardcoded list anywhere: it can only come from reading verify.sh. @@ -4450,7 +4462,7 @@ if c61_trust "$c61_a"; then grep -q '/scripts/ci\.sh$' "$(c61_store "$c61_a")" \ || c61_errs="$c61_errs\nvstack trust did not record scripts/ci.sh, a path only verify.sh names -- the scan is not reading the gate" else - c61_errs="$c61_errs\nvstack trust failed on a synthetic repo naming ./scripts/ci.sh" + c61_errs="$c61_errs\nvstack trust failed on a synthetic repo naming ./scripts/ci.sh -- $c61_last" fi # Lane 3 -- negative control. A gate that runs nothing else gets one entry. Without this, lane 2 @@ -4463,13 +4475,15 @@ if c61_trust "$c61_b"; then [ "$c61_n" = 1 ] \ || c61_errs="$c61_errs\nvstack trust recorded $c61_n entries for a gate that names no other script; it should record 1" else - c61_errs="$c61_errs\nvstack trust failed on a synthetic repo naming nothing" + c61_errs="$c61_errs\nvstack trust failed on a synthetic repo naming nothing -- $c61_last" fi # Lane 4 -- this repository. The two files the narrow writer missed, named because they are the # ones verify.sh actually executes, not because they are a general category. c61_c="$c61_d/c"; mkdir -p "$c61_c/home" -if HOME="$c61_c/home" ./bin/vstack trust "$PWD" --yes >/dev/null 2>&1; then +if c61_last=$(HOME="$c61_c/home" ./bin/vstack trust "$PWD" --yes 2>&1 >/dev/null); c61_rc=$?; \ + c61_last="rc=$c61_rc, stderr: $(printf '%s' "${c61_last:-(nothing on stderr)}" | tr '\n' ' ')"; \ + [ "$c61_rc" -eq 0 ]; then for c61_f in install.sh overlay.sh; do grep -q "/$c61_f\$" "$(c61_store "$c61_c")" \ || c61_errs="$c61_errs\nthe trust store for this repo does not record $c61_f, which .claude/verify.sh executes" @@ -4477,7 +4491,7 @@ if HOME="$c61_c/home" ./bin/vstack trust "$PWD" --yes >/dev/null 2>&1; then c61_tot=$(grep -c . "$(c61_store "$c61_c")" || true) else c61_tot=0 - c61_errs="$c61_errs\nvstack trust failed on this repository" + c61_errs="$c61_errs\nvstack trust failed on this repository -- $c61_last" fi rm -rf "$c61_d" diff --git a/tests/container-matrix.sh b/tests/container-matrix.sh index 1279677..f360e5e 100755 --- a/tests/container-matrix.sh +++ b/tests/container-matrix.sh @@ -81,8 +81,8 @@ fi cat > "$ROOT/bootstrap-apk.sh" <<'EOF' #!/bin/sh set -e -apk add --no-cache bash git jq curl ca-certificates shellcheck 2>&1 || \ - apk add --no-cache bash git jq curl ca-certificates 2>&1 +apk add --no-cache bash git jq curl ca-certificates shellcheck python3 2>&1 || \ + apk add --no-cache bash git jq curl ca-certificates python3 2>&1 EOF cat > "$ROOT/bootstrap-apt.sh" <<'EOF' @@ -90,8 +90,8 @@ cat > "$ROOT/bootstrap-apt.sh" <<'EOF' set -e export DEBIAN_FRONTEND=noninteractive apt-get update -qq -apt-get install -y -qq --no-install-recommends git jq curl ca-certificates shellcheck || \ - apt-get install -y -qq --no-install-recommends git jq curl ca-certificates +apt-get install -y -qq --no-install-recommends git jq curl ca-certificates shellcheck python3 || \ + apt-get install -y -qq --no-install-recommends git jq curl ca-certificates python3 EOF # --- the in-container assertion runner ---------------------------------------------------------- @@ -193,10 +193,20 @@ if [ -x "$DOCTOR" ]; then # of .claude/verify.sh fails if either stops reading it or if the list grows. _pt_file="/work/repo/tests/pretag-findings.sh" if [ -f "$_pt_file" ]; then . "$_pt_file"; else PRETAG_ALLOWED_FINDING=""; fi - _dr_x=$(grep '✖' /tmp/doctor.out | grep -vF "$PRETAG_ALLOWED_FINDING") + # bin/doctor's closing line is `DRIFT ✖` for ANY non-zero FAIL count -- it is the summary + # banner, not a drift finding, and it name-collides with one. Left in the residual it made the + # carve-out unreachable by construction: with the allowed finding as the SOLE failure, _dr_x + # was still non-empty, holding a line with no diagnostic content, and every image reported + # `doctor exit=1; DRIFT ✖`. Dropping it does not soften anything -- each individual finding + # prints its own ✖ line, so a second, real failure still lands in the residual. What is added + # below is the guard that the banner was accidentally providing: the allowed finding must + # actually be present, or a doctor that failed while printing no findings at all would pass. + _dr_x=$(grep '✖' /tmp/doctor.out | grep -vF "$PRETAG_ALLOWED_FINDING" | grep -vxF 'DRIFT ✖') if [ "$rc" -eq 0 ]; then res PASS "2-doctor-exit0" "doctor exit=$rc" elif [ -z "$_pt_file" ] || [ ! -f "$_pt_file" ]; then res FAIL "2-doctor-exit0" "doctor exit=$rc and $_pt_file is missing, so the pre-tag carve-out cannot be applied; $(grep '✖' /tmp/doctor.out | tr '\n' ';')" + elif ! grep -qF "$PRETAG_ALLOWED_FINDING" /tmp/doctor.out; then + res FAIL "2-doctor-exit0" "doctor exit=$rc but did not report '$PRETAG_ALLOWED_FINDING' at all, so the carve-out is excusing a failure it cannot see; $(grep '✖' /tmp/doctor.out | tr '\n' ';')" elif [ -z "$_dr_x" ]; then res PASS "2-doctor-exit0" "doctor exit=$rc, only finding is '$PRETAG_ALLOWED_FINDING', a note in a commit-triggered lane" else res FAIL "2-doctor-exit0" "doctor exit=$rc; $(printf '%s' "$_dr_x" | tr '\n' ';')"; fi From 61bd63beffd02275e43dcd3f6b2d415a6cf0cc02 Mon Sep 17 00:00:00 2001 From: vk Date: Tue, 1 Sep 2026 17:27:55 +0530 Subject: [PATCH 2/2] Name $VSTACK_DIR in check 61, the thing its own HOME override hid The Alpine stderr, once the check stopped discarding it: `vstack: no vstack repo found (checked $VSTACK_DIR, ~/.vstack, and this script's git root)`, rc=1, all three lanes. Not a portability defect in `vstack trust` and nothing to do with shasum, which was ruled out against a byte-identical image. Check 61 redirects HOME so each lane writes its own trust store instead of the operator's. That also hides ~/.vstack and the global gitconfig. bin/vstack resolves its repo from $VSTACK_DIR, then ~/.vstack, then `git rev-parse --show-toplevel`; under a foreign HOME the first two are gone, and in the Alpine container the third fails as well, because actions/checkout writes its safe.directory exemption into the runner HOME's gitconfig and the override hides it, so git refuses the checkout as dubiously owned. bin/vstack exits before `trust` runs. Proven: the message, the rc, and that it is Alpine-only. Inferred: that the git-root lane lost on dubious ownership specifically -- the message does not say which of the three failed. Naming $VSTACK_DIR settles it either way and is what the error text tells you to do. The check's own environment, not a defect in what it measures. A user does not run vstack under a substituted HOME. What made it expensive is that the invocation threw away stderr, so one platform went red with a sentence that could not distinguish this from a broken hasher. Co-Authored-By: Claude Opus 5 (1M context) --- .claude/verify.sh | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/.claude/verify.sh b/.claude/verify.sh index ea22db3..cd7c9b1 100755 --- a/.claude/verify.sh +++ b/.claude/verify.sh @@ -4445,9 +4445,25 @@ c61_store(){ printf '%s' "$1/home/.config/agents/verify-trust"; } # was run with `>/dev/null 2>&1` -- a check that knows something is wrong and has thrown away the # only sentence saying what. Two reproduction attempts against a byte-identical image failed to # make it fail, which is exactly the case where the swallowed stderr is the whole investigation. +# VSTACK_DIR is set for the same reason HOME is overridden, and the two interact. HOME is +# redirected so each lane gets its own trust store instead of writing the operator's. That also +# hides ~/.vstack and the global gitconfig, and bin/vstack resolves its repo from $VSTACK_DIR, +# then ~/.vstack, then `git rev-parse --show-toplevel`. Under a foreign HOME the first two are +# gone, and inside the Alpine CI container the third fails too -- actions/checkout writes its +# safe.directory exemption into the runner HOME's gitconfig, which the override hides, so git +# refuses the checkout as dubiously owned. bin/vstack then exits 1 before `trust` runs at all. +# +# PROVEN: the three lanes reported `no vstack repo found (checked $VSTACK_DIR, ~/.vstack, and +# this script's git root)`, rc=1, on Alpine only. INFERRED: that the git-root lane failed +# specifically on dubious ownership; the message does not say which of the three lost. Naming +# $VSTACK_DIR settles it either way, and it is what the error text itself tells you to do. +# +# This is the check's own environment, not a defect in what it measures: a user does not run +# vstack under a substituted HOME. It cost a red on one platform and three destroyed tags' +# worth of noise because the invocation discarded stderr. c61_last="" c61_trust(){ - c61_last=$(HOME="$1/home" ./bin/vstack trust "$1" --yes 2>&1 >/dev/null) + c61_last=$(HOME="$1/home" VSTACK_DIR="$PWD" ./bin/vstack trust "$1" --yes 2>&1 >/dev/null) c61_rc=$? [ -n "$c61_last" ] || c61_last="(command printed nothing on stderr)" c61_last="rc=$c61_rc, stderr: $(printf '%s' "$c61_last" | tr '\n' ' ')" @@ -4481,7 +4497,7 @@ fi # Lane 4 -- this repository. The two files the narrow writer missed, named because they are the # ones verify.sh actually executes, not because they are a general category. c61_c="$c61_d/c"; mkdir -p "$c61_c/home" -if c61_last=$(HOME="$c61_c/home" ./bin/vstack trust "$PWD" --yes 2>&1 >/dev/null); c61_rc=$?; \ +if c61_last=$(HOME="$c61_c/home" VSTACK_DIR="$PWD" ./bin/vstack trust "$PWD" --yes 2>&1 >/dev/null); c61_rc=$?; \ c61_last="rc=$c61_rc, stderr: $(printf '%s' "${c61_last:-(nothing on stderr)}" | tr '\n' ' ')"; \ [ "$c61_rc" -eq 0 ]; then for c61_f in install.sh overlay.sh; do