#!/usr/bin/env bash # Step 6b — per-target SC2/SC7 gate with the migration's REGRESSION-RELATIVE contract baked in. # # WHY THIS EXISTS: 40-validate-standalone.sh is STRICT — any standalone test failure exits non-zero. The # migration's RATIFIED contract — the one the Step-11 dry-run (99-dryrun.sh) validated and signed off as # "PASS 11/11" — is weaker and correct: a target passes iff the extraction introduces NO NEW failure. # Pre-existing in-repo red (voyage's 2 doc-consistency drifts re phase_models/phase_signals; ai-psychosis's # 1) is the PLUGIN's own concern, not a migration regression. The operator window (run-operator-window.sh # step [a]) must enforce THAT contract, not a stricter one — otherwise it STOPs on the first target carrying # pre-existing red even though the dry-run blessed it (the bug this script fixes). This is the single # per-target gate the window calls; it mirrors 99-dryrun.sh's SC2 decision exactly, reusing capture-fails.sh # (the failing-name capture) + sc2-regression.sh (the subset decision). NULL push (D8): read-only validation. # # CONTRACT: # - sc2_gate target (config-audit): the dedicated gate is deterministic — run it STRICT (PASS/FAIL). # - else: run 40-validate-standalone.sh STRICT. PASS => exit 0. # On FAIL, only a `node --test` suite is regression-eligible: its standalone failing-NAME set must be # a SUBSET of the live in-repo failing-NAME set (regression-relative PASS, "PASS (N pre-existing)"). # A structure-validator (validate-plugin*.sh / bash -c) FAIL is a genuine structural defect — NOT # softened. A genuine regression (standalone-only failure) or a missing capture => exit non-zero. # Escalate, never mask: any real regression or structural failure exits non-zero so the window STOPs. # # Usage: 41-validate-or-regression.sh set -uo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" MAP="$SCRIPT_DIR/plugin-map.json" REPO_ROOT="$(cd "$SCRIPT_DIR/../../.." && pwd)" WORK="${WORK:-/tmp/polyrepo-migration}" [ -f "$MAP" ] || { echo "plugin-map.json missing at $MAP" >&2; exit 2; } key="${1:?usage: 41-validate-or-regression.sh }" mapget() { python3 -c "import json;print(json.load(open('$MAP'))['targets']['$key'].get('$1',''))"; } sc2_gate="$(mapget sc2_gate)" test_cmd="$(mapget test_cmd)" # --- gate target (config-audit): deterministic, strict by design --- if [ -n "$sc2_gate" ]; then if WORK="$WORK" bash "$SCRIPT_DIR/$sc2_gate" >/dev/null 2>&1; then echo "$key: PASS ($sc2_gate)"; exit 0 fi echo "$key: FAIL ($sc2_gate)" >&2; exit 1 fi # --- strict standalone validation first (SC2 + SC7 + per-target structural checks) --- if WORK="$WORK" bash "$SCRIPT_DIR/40-validate-standalone.sh" "$key" >/dev/null 2>&1; then echo "$key: PASS (standalone strict)"; exit 0 fi # Strict failed. Only a node:test suite can fail regression-relative-acceptably; a structure validator # failing is a genuine structural defect — do not soften it. case "$test_cmd" in *node\ --test*) : ;; *) echo "$key: FAIL (standalone strict; structure validator — not regression-eligible)" >&2; exit 1 ;; esac dest="$WORK/$key" [ -d "$dest/.git" ] || { echo "$key: FAIL (no prepped extract at $dest — run 40-validate-standalone.sh first)" >&2; exit 1; } # Regression-relative: the standalone failing-NAME set must be a SUBSET of the live in-repo failing-NAME set. # Capture the standalone set from the PREPPED EXTRACT ($WORK/$key), NOT 40's /tmp/claude-$key side-effect # clean room (4e494c8: that coupling masked a real regression when the dir was absent). The subset decision # is delegated to sc2-regression.sh; a missing capture FILE there is a hard error, never a false PASS. sf="$(mktemp)" && bf="$(mktemp)" || { echo "$key: FAIL (mktemp)" >&2; exit 1; } trap 'rm -f "$sf" "$bf"' EXIT bash "$SCRIPT_DIR/capture-fails.sh" "$dest" "$test_cmd" > "$sf" 2>/dev/null bash "$SCRIPT_DIR/capture-fails.sh" "$REPO_ROOT/plugins/$key" "$test_cmd" > "$bf" 2>/dev/null pre="$(wc -l < "$bf" | tr -d '[:space:]')" if regr="$(bash "$SCRIPT_DIR/sc2-regression.sh" "$sf" "$bf")"; then echo "$key: PASS (${pre} pre-existing, regression-relative)" exit 0 else rc=$? if [ "$rc" -ge 2 ]; then echo "$key: FAIL (sc2-regression error — missing capture file)" >&2 else echo "$key: FAIL (regression: $(printf '%s' "$regr" | grep -c .) new failure(s) absent from in-repo baseline):" >&2 printf '%s\n' "$regr" >&2 fi exit 1 fi