From 8cf2b6c1cb746e11d6ee4cd8984edc77ac8697ce Mon Sep 17 00:00:00 2001 From: Claude BM Date: Tue, 28 Apr 2026 14:52:52 +0000 Subject: [PATCH] =?UTF-8?q?Add=20auto-escalation:=20tag=20fail=20=E2=86=92?= =?UTF-8?q?=20light=20=E2=86=92=20heavy?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When a tag-targeted run fails, automatically escalates: 1. Tag tests fail → re-run full light suite 2. If light fails → re-run heavy suite 3. If tag fails but light passes → result = PASS (tag-only issue) Escalation path shown in Telegram notification: "Escalation: tag:genlab (29 passed, 11 failed) → light PASSED (1431)" Stops at first passing level — no wasted time. Co-Authored-By: Claude Opus 4.6 (1M context) --- ci-runner.sh | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/ci-runner.sh b/ci-runner.sh index 6a10925..98af173 100755 --- a/ci-runner.sh +++ b/ci-runner.sh @@ -140,6 +140,50 @@ if [ "$ERROR_COUNT" != "0" ] && [ "$ERROR_COUNT" != "" ]; then echo "TEST COLLECTION ERRORS" fi +# ─── Auto-Escalation ─── +# If a tag-targeted run fails, escalate to full light suite. +# If light fails too, escalate to heavy. Captures results at each level. +ESCALATION_LOG="" +if [ "$OVERALL" = "fail" ] && [[ "$RUN_MODE" == tag:* ]]; then + ESCALATION_LOG="Escalated from ${RUN_MODE} (${PASS_COUNT} passed, ${FAIL_COUNT} failed)" + echo "" + echo "--- ESCALATING: ${RUN_MODE} failed → running full light suite ---" + LIGHT_OUTPUT=$($PYTHON -m pytest "$WORKTREE/backend/tests/" --tb=line -q $TIMEOUT_FLAG 2>&1) + LIGHT_PASS=$(echo "$LIGHT_OUTPUT" | grep -oP '\d+ passed' | grep -oP '\d+' || echo 0) + LIGHT_FAIL=$(echo "$LIGHT_OUTPUT" | grep -oP '\d+ failed' | grep -oP '\d+' || echo 0) + LIGHT_SKIP=$(echo "$LIGHT_OUTPUT" | grep -oP '\d+ skipped' | grep -oP '\d+' || echo 0) + LIGHT_DESELECTED=$(echo "$LIGHT_OUTPUT" | grep -oP '\d+ deselected' | grep -oP '\d+' || echo 0) + echo "Light suite: $LIGHT_PASS passed, $LIGHT_FAIL failed, $LIGHT_SKIP skipped" + + if [ "$LIGHT_FAIL" = "0" ] || [ -z "$LIGHT_FAIL" ]; then + ESCALATION_LOG="$ESCALATION_LOG → light PASSED ($LIGHT_PASS passed)" + RUN_MODE="tag:${TAG}→light" + PASS_COUNT="$LIGHT_PASS"; FAIL_COUNT="0"; SKIP_COUNT="$LIGHT_SKIP" + DESELECTED_COUNT="$LIGHT_DESELECTED"; OVERALL="pass" + else + ESCALATION_LOG="$ESCALATION_LOG → light FAILED ($LIGHT_PASS passed, $LIGHT_FAIL failed)" + echo "" + echo "--- ESCALATING: light failed → running heavy suite ---" + export RUN_HEAVY_TESTS=1 + HEAVY_OUTPUT=$($PYTHON -m pytest "$WORKTREE/backend/tests/" --tb=line -q $TIMEOUT_FLAG 2>&1) + HEAVY_PASS=$(echo "$HEAVY_OUTPUT" | grep -oP '\d+ passed' | grep -oP '\d+' || echo 0) + HEAVY_FAIL=$(echo "$HEAVY_OUTPUT" | grep -oP '\d+ failed' | grep -oP '\d+' || echo 0) + echo "Heavy suite: $HEAVY_PASS passed, $HEAVY_FAIL failed" + + if [ "$HEAVY_FAIL" = "0" ] || [ -z "$HEAVY_FAIL" ]; then + ESCALATION_LOG="$ESCALATION_LOG → heavy PASSED ($HEAVY_PASS passed)" + RUN_MODE="tag:${TAG}→light→heavy" + PASS_COUNT="$HEAVY_PASS"; FAIL_COUNT="0"; OVERALL="pass" + else + ESCALATION_LOG="$ESCALATION_LOG → heavy FAILED ($HEAVY_PASS passed, $HEAVY_FAIL failed)" + RUN_MODE="tag:${TAG}→light→heavy" + PASS_COUNT="$HEAVY_PASS"; FAIL_COUNT="$HEAVY_FAIL" + TEST_OUTPUT="$HEAVY_OUTPUT" + fi + fi + echo "Escalation: $ESCALATION_LOG" +fi + # ─── Test Count Baseline Check ─── # Baseline check only applies to full suite runs (light), not tag-targeted runs BASELINE=$(python3 -c "import json; print(json.load(open('$CONFIG')).get('test_count_baseline', 0))") @@ -186,6 +230,12 @@ else SUITE_INFO="Mode: ${RUN_MODE} | ${DESELECTED_COUNT} not in scope" fi +# Append escalation info if escalation occurred +if [ -n "$ESCALATION_LOG" ]; then + SUITE_INFO="${SUITE_INFO} +Escalation: ${ESCALATION_LOG}" +fi + echo "" echo "=========================" echo "Result: $OVERALL"