test(git-tools): wrapper-guard harness distinguishes tool failure from drift (#1380-FF)
ci/woodpecker/pr/ci Pipeline failed
ci/woodpecker/pr/ci Pipeline failed
Pipeline 2635 (merge-verify of 8eb7e635) failed one advice assertion
('a PR is an issue where labels live...') while pipeline 2634 (same
content, PR event) and 2636 (same tree + one commit) both passed, and the
fixture is stable under 200 direct iterations, 10 suite runs, four
locales, and 60 suite runs inside alpine/busybox 1.37 (the CI userspace).
Mechanism: the harness's 'if ! ... | grep -Fq' shape treats ANY nonzero
from the pipeline as an advice mismatch — including a transient grep
failure (fork/alloc error on a loaded k8s node), which prints the
identical FAIL line without any guard defect. The guard's rc-2 sites were
audited: every classification branch that can fire on this payload names
issue-edit.sh, so no code path produces the observed output.
Fix: the advice assertion now retries grep on rc>=2 (tool error) up to
3x, treats rc=1 as the real mismatch, and on persistent tool failure
prints a distinct TOOL-ERROR line (still fail=1 — never green on
infra noise, but the line names the class so a re-run can be judged
instead of debugged as guard drift). Advice-mismatch direction proven
unchanged by mutation (bogus wrapper name still FAILs both labels arms).
Suite 292/292 x2 locally and under busybox.
This commit is contained in:
@@ -521,6 +521,26 @@ while IFS=$'\t' read -r want payload why remedy; do
|
||||
n=$((n + 1))
|
||||
out="$(printf '%s' "$payload" | "$GUARD" 2>&1)"
|
||||
got=$?
|
||||
# Flake containment (stack#1380-FF, pipeline 2635): a transient failure of
|
||||
# the ASSERTION TOOLING (grep/fork/alloc error under node pressure) is not a
|
||||
# contract drift, but this loop's `if !` shape made it indistinguishable
|
||||
# from one — the harness printed the advice-mismatch FAIL and failed a merge
|
||||
# verify on a run whose guard output was correct. Distinguish the two: an
|
||||
# assertion tool that itself fails is retried a bounded number of times, and
|
||||
# if it never succeeds the case reports a TOOL-ERROR line (fail=1 stays, so
|
||||
# the run is never green-on-infra-noise, but the line names the real class
|
||||
# and a re-run can be judged instead of debugged as a guard defect).
|
||||
assert_out_names() {
|
||||
local attempt rc1
|
||||
for attempt in 1 2 3; do
|
||||
printf '%s' "$out" | grep -Fq -- "$1" && return 0
|
||||
rc1=$?
|
||||
[ "$rc1" -eq 1 ] && return 1 # grep answered NO — real mismatch
|
||||
sleep 0.2 # rc>=2: grep itself errored — retry
|
||||
done
|
||||
printf 'TOOL-ERROR %s (assertion grep failed 3x; guard output was correct class — infra/tooling, not guard drift)\n' "$why" >&2
|
||||
return 2
|
||||
}
|
||||
if [ "$got" != "$want" ]; then
|
||||
printf 'FAIL %s (want exit %s, got %s)\n' "$why" "$want" "$got"
|
||||
fail=1
|
||||
@@ -530,10 +550,15 @@ while IFS=$'\t' read -r want payload why remedy; do
|
||||
# now it was invisible here: the harness read the exit code and nothing else,
|
||||
# so /issues/1/labels blocking with "use issue-create.sh" passed every run for
|
||||
# six rounds. Where a fixture states the remediation it expects, assert it.
|
||||
if [ -n "${remedy:-}" ] && ! printf '%s' "$out" | grep -Fq -- "$remedy"; then
|
||||
printf 'FAIL %s (blocked, but the advice does not name %s)\n' "$why" "$remedy"
|
||||
fail=1
|
||||
continue
|
||||
if [ -n "${remedy:-}" ]; then
|
||||
assert_out_names "$remedy"
|
||||
arcret=$?
|
||||
if [ "$arcret" -eq 1 ]; then
|
||||
printf 'FAIL %s (blocked, but the advice does not name %s)\n' "$why" "$remedy"
|
||||
fail=1
|
||||
continue
|
||||
fi
|
||||
[ "$arcret" -eq 0 ] || { fail=1; continue; }
|
||||
fi
|
||||
printf 'ok %s\n' "$why"
|
||||
done < "$FIXTURES"
|
||||
|
||||
Reference in New Issue
Block a user