50-config-audit-sc2.sh: re-seeds snapshot-default-output in-clone (UPDATE_SNAPSHOT=1), then runs the SC2 gate = full 'find tests -name *.test.mjs' MINUS the 6-file machine-locked v5.0.0 byte-stability surface. 730 tests across 46 files pass standalone. templates/validate-plugin.generic.sh: ported, parameterized structure validator for the two test-less plugins (okr, human-friendly-style) — STRUCTURE OK on valid plugin.json + non-empty surface + parseable frontmatter; STRUCTURE FAIL otherwise. Reuses the claude-design/tests/validate-plugin.sh pattern. Brief-correction (operator-ratified 2026-06-17): plan F4 named only json-backcompat + raw-backcompat (2 files). The verified machine-locked surface is 6 — the v5.0.0 fixtures embed the original absolute path AND the claude_md/plugin_hygiene scanners key off a plugins/ ancestor, so findings drift by path (behavioral, not a string rewrite). Dropped clean-room SC2 coverage = config-audit's humanizer/posture-humanizer/scan-orchestrator-humanizer prose-snapshot surface, recorded in the script header + plugin-map.json (not silent). The 3 other v5.0.0-referencing tests (posture, scoring-humanizer, scenario-read-test) are path-independent and stay in the gate. config-audit backlog (out of migration scope): normalize the v5.0.0 fixtures + path-agnostic scanners, then re-include. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
93 lines
5.8 KiB
Bash
93 lines
5.8 KiB
Bash
#!/usr/bin/env bash
|
|
# Step 7 — Resolve the config-audit SC2 blocker for standalone extraction.
|
|
#
|
|
# config-audit declares its runner as `node --test 'tests/**/*.test.mjs'` (52 files, CLAUDE.md:109).
|
|
# Two distinct, directly-verified portability defects block a clean-room SC2 gate at a new clone path:
|
|
#
|
|
# (a) REBASABLE — tests/snapshot-default-output.test.mjs asserts byte-equal CLI stdout whose deep
|
|
# per-file paths are NOT normalized (normalizeScanOrchestrator scrubs only meta.target/timestamp/
|
|
# duration_ms), so it breaks at a fresh clone path. FIX: re-seed in-clone via the test's own
|
|
# intended re-approval seam — `UPDATE_SNAPSHOT=1 node --test tests/snapshot-default-output.test.mjs`
|
|
# (seam documented at its line 33). After re-seeding it asserts byte-equal against the clone's
|
|
# own path and passes.
|
|
#
|
|
# (b) FROZEN / MACHINE-LOCKED — a family of tests assert byte/structure equality against the
|
|
# tests/snapshots/v5.0.0/ fixtures, which deliberately embed the ORIGINAL capture machine's
|
|
# absolute path + a sibling marketplace + deleted plugins. At a fresh clone path they break in
|
|
# TWO ways (both verified directly, 2026-06-17): a literal embedded `path:` mismatch, AND a
|
|
# BEHAVIORAL drift — the claude_md / plugin_hygiene scanners key off whether a `plugins/<name>/`
|
|
# ancestor exists in the absolute path, so the clone produces different findingCount/score than
|
|
# the monorepo capture (e.g. posture-humanizer). drift-cli's baseline diff additionally leaks the
|
|
# clone path into humanized prose, which trips lint-default-output's tier1/tier3 prose gate.
|
|
# Regenerating these would defeat their byte-stability purpose and "normalize the path" is not a
|
|
# string rewrite (the scan BEHAVIOR differs by path) — so the correct migration-scope fix is to
|
|
# EXCLUDE the machine-locked surface by name (deterministic enumeration, no invented env var).
|
|
#
|
|
# OPERATOR-RATIFIED 2026-06-17 (brief-correction): plan F4 named only json-backcompat +
|
|
# raw-backcompat (2 files). The verified machine-locked surface is SIX files (the 2 + the 4 that
|
|
# still fail at clone path). Dropped clean-room SC2 coverage = config-audit's humanizer / posture-
|
|
# humanizer / scan-orchestrator-humanizer prose-snapshot surface (NOT silent — recorded here +
|
|
# in plugin-map.json's standalone_caveat). The three OTHER v5.0.0-referencing tests
|
|
# (posture, scoring-humanizer, scenario-read-test) assert path-INDEPENDENT aspects, pass at the
|
|
# clone path, and remain IN the gate. config-audit backlog (out of migration scope): normalize
|
|
# the v5.0.0 fixtures' embedded paths + make the scanners path-agnostic, then re-include.
|
|
#
|
|
# SC2 gate (config-audit) := full `find tests -name '*.test.mjs'` MINUS the six machine-locked tests
|
|
# below, run AFTER the in-clone snapshot re-seed. NULL push (D8). Prints "config-audit: SC2 PASS (...)"
|
|
# + exit 0 on success; non-zero on any failure (escalate — never mask).
|
|
#
|
|
# Usage: 50-config-audit-sc2.sh
|
|
set -uo pipefail
|
|
unset NODE_TEST_CONTEXT 2>/dev/null || true # un-nest the internal `node --test` (Node 25 count suppression)
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
WORK="${WORK:-/tmp/polyrepo-migration}"
|
|
KEY="config-audit"
|
|
DEST="$WORK/$KEY"
|
|
CR="/tmp/claude-${KEY}-sc2"
|
|
|
|
# The machine-locked v5.0.0 byte-stability surface excluded from the SC2 gate (operator-ratified).
|
|
# Anchored to each test file's basename; scan-orchestrator-humanizer is matched WITHOUT catching the
|
|
# portable scan-orchestrator.test.mjs, and posture-humanizer WITHOUT catching posture.test.mjs.
|
|
EXCLUDE_RE='(json-backcompat|raw-backcompat|cli-humanizer|posture-humanizer|scan-orchestrator-humanizer|lint-default-output)\.test\.mjs$'
|
|
|
|
# --- 1. Prep the extract (idempotent), reusing the Step 3-5 drivers (same pattern as 40-validate-standalone.sh) ---
|
|
if [ ! -d "$DEST/.git" ]; then
|
|
WORK="$WORK" bash "$SCRIPT_DIR/10-extract.sh" "$KEY" >/dev/null || { echo "config-audit: SC2 FAIL (extract error)"; exit 1; }
|
|
fi
|
|
WORK="$WORK" bash "$SCRIPT_DIR/20-rehome-config.sh" "$KEY" >/dev/null || { echo "config-audit: SC2 FAIL (rehome error)"; exit 1; }
|
|
WORK="$WORK" node "$SCRIPT_DIR/30-fix-references.mjs" "$KEY" >/dev/null || { echo "config-audit: SC2 FAIL (fix-references error)"; exit 1; }
|
|
|
|
# --- 2. Clean room (no marketplace parent) ---
|
|
rm -rf "$CR"
|
|
cp -R "$DEST" "$CR"
|
|
|
|
# --- 3. Re-seed the rebasable snapshot at the clone's own path (intended re-approval seam) ---
|
|
if [ ! -f "$CR/tests/snapshot-default-output.test.mjs" ]; then
|
|
echo "config-audit: SC2 FAIL (snapshot test missing from extract)"; exit 1
|
|
fi
|
|
( cd "$CR" && UPDATE_SNAPSHOT=1 node --test tests/snapshot-default-output.test.mjs ) >/dev/null 2>&1 \
|
|
|| { echo "config-audit: SC2 FAIL (snapshot re-seed error)"; exit 1; }
|
|
|
|
# --- 4. Build the gate: full suite MINUS the machine-locked v5.0.0 back-compat tests (excluded by name) ---
|
|
GATE_FILES="$(cd "$CR" && find tests -name '*.test.mjs' | grep -vE "$EXCLUDE_RE" | sort)"
|
|
if [ -z "$GATE_FILES" ]; then echo "config-audit: SC2 FAIL (no gate files enumerated)"; exit 1; fi
|
|
|
|
# Defense-in-depth: none of the machine-locked tests may leak into the gate.
|
|
if printf '%s\n' "$GATE_FILES" | grep -qE "$EXCLUDE_RE"; then
|
|
echo "config-audit: SC2 FAIL (machine-locked exclusion leaked into the gate)"; exit 1
|
|
fi
|
|
GATE_COUNT="$(printf '%s\n' "$GATE_FILES" | wc -l | tr -d '[:space:]')"
|
|
|
|
# --- 5. Run the gate in the clean room ---
|
|
OUT="$(cd "$CR" && node --test $GATE_FILES 2>&1)"; STATUS=$?
|
|
TESTS="$(printf '%s\n' "$OUT" | grep -oE 'tests [0-9]+' | grep -oE '[0-9]+' | tail -1)"
|
|
|
|
if [ "$STATUS" -ne 0 ]; then
|
|
echo "config-audit: SC2 FAIL (gate exit $STATUS)"
|
|
printf '%s\n' "$OUT" | tail -25
|
|
exit 1
|
|
fi
|
|
|
|
echo "config-audit: SC2 PASS (${TESTS:-?} tests across ${GATE_COUNT} files, full suite minus the 6-file v5.0.0 byte-stability surface, standalone-safe)"
|
|
exit 0
|