#!/usr/bin/env bash # Covers the structure-anchor provisioning check in `mosaic-doctor` (T51 WP0b). # # Same discipline as test-brain-home-check.sh: functions are extracted from the # shipped script (exact header + closing brace), never copied — a test carrying # its own copy of the logic keeps passing after the shipped copy changes. # # Four contract states (charter T51P2WP0B-20260824): # 1. both present+nonempty -> pass ([OK]), no warns, no notes # 2a. host missing, brain set -> warn naming MOSAIC_HOST_ROOT + launchers # 2b. brain missing, host set -> warn naming MOSAIC_BRAIN_HOME + launchers # 2c. present-but-EMPTY counts as missing (warns; NEVER informational) # 3. neither present -> informational notes, NON-AUTHORITATIVE, never warn # Arms include genuinely-UNSET (env -u) forms, not only empty strings. # Red control: empty-vs-unset distinction removed in a mutated copy -> suite red. set -euo pipefail SCRIPT_DIR=$(cd -- "$(dirname "$0")" && pwd) DOCTOR="$SCRIPT_DIR/mosaic-doctor" fail() { echo "FAIL: $*" >&2 exit 1 } [ -f "$DOCTOR" ] || fail "missing mosaic-doctor at $DOCTOR" extract_function() { local name="$1" local extracted extracted=$(sed -n "/^${name}() {/,/^}/p" "$DOCTOR") [ -n "$extracted" ] || fail "could not extract ${name}() from mosaic-doctor — script reshaped?" printf '%s\n' "$extracted" } for fn in check_structure_anchor_provisioning; do extract_function "$fn" >/dev/null done # run_case LABEL EXPECT(ok|warn|note) [env assignments as args; -u VAR tokens for unset] run_case() { local label="$1" expect="$2" shift 2 local envs=() unsets=() local a for a in "$@"; do case "$a" in -u:*) unsets+=("${a#-u:}") ;; *) envs+=("$a") ;; esac done local out warns notes oks # build the env command with proper -u flags (array expansion must not # glue '-u VAR' into one word) local cmd=(env) local e u # env(1) parses options only before the first assignment — -u flags FIRST for u in "${unsets[@]:-}"; do [ -n "$u" ] && cmd+=(-u "$u"); done for e in "${envs[@]:-}"; do [ -n "$e" ] && cmd+=("$e"); done cmd+=(bash -c "warn() { echo \"[WARN] \$*\"; }; note() { echo \"[NOTE] \$*\"; return 0; }; pass() { echo \"[OK] \$*\"; return 0; }; $(extract_function check_structure_anchor_provisioning); check_structure_anchor_provisioning") out=$("${cmd[@]}" 2>&1) warns=$(printf '%s\n' "$out" | grep -c '^\[WARN\]' || true) notes=$(printf '%s\n' "$out" | grep -c '^\[NOTE\]' || true) oks=$(printf '%s\n' "$out" | grep -c '^\[OK\]' || true) if [[ "$expect" == ok && "$oks" -gt 0 && "$warns" -eq 0 && "$notes" -eq 0 ]]; then echo "ok - $label" elif [[ "$expect" == warn && "$warns" -ge 1 && "$notes" -eq 0 ]]; then echo "ok - $label (warned x$warns)" elif [[ "$expect" == note && "$notes" -gt 0 && "$warns" -eq 0 ]]; then echo "ok - $label (noted)" else echo "output: $out" >&2 fail "$label: expected $expect (oks=$oks warns=$warns notes=$notes)" fi } ROOT=$(mktemp -d) trap 'rm -rf "$ROOT"' EXIT HOST="$ROOT/host" BRAIN="$ROOT/brain" # ── state 1: both present + nonempty → pass ──────────────────────────────── run_case "both anchors present passes" ok \ MOSAIC_HOST_ROOT="$HOST" MOSAIC_BRAIN_HOME="$BRAIN" # ── state 2a: host missing (unset), brain set → exactly one warn ─────────── run_case "unset host root warns" warn \ -u:MOSAIC_HOST_ROOT MOSAIC_BRAIN_HOME="$BRAIN" # ── state 2b: brain missing (unset), host set → exactly one warn ─────────── run_case "unset brain home warns" warn \ MOSAIC_HOST_ROOT="$HOST" -u:MOSAIC_BRAIN_HOME # ── state 2c-empty: present-but-empty counts as missing ──────────────────── run_case "empty-string host root warns (empty != set)" warn \ MOSAIC_HOST_ROOT= MOSAIC_BRAIN_HOME="$BRAIN" run_case "empty-string brain home warns (empty != set)" warn \ MOSAIC_HOST_ROOT="$HOST" MOSAIC_BRAIN_HOME= # ── state 3: neither present (genuinely unset) → notes, never warn ───────── run_case "both unset yields non-authoritative notes" note \ -u:MOSAIC_HOST_ROOT -u:MOSAIC_BRAIN_HOME run_case "both empty-string warns (empty is present, not absent)" warn \ MOSAIC_HOST_ROOT= MOSAIC_BRAIN_HOME= run_case "host empty + brain unset warns" warn \ MOSAIC_HOST_ROOT= -u:MOSAIC_BRAIN_HOME run_case "host unset + brain empty warns" warn \ -u:MOSAIC_HOST_ROOT MOSAIC_BRAIN_HOME= # ── red control (mutation): presence tracking removed → red ──────────────── # Mutant regresses to the reviewed defect shape: presence derived from # NONEMPTINESS (the `${VAR:-}` collapse) instead of true -v tracking. Both-empty # then looks genuinely-absent and is mis-filed as informational; the both-empty # warn arm above finds no WARN and the suite reds. MUT="$ROOT/mosaic-doctor.mutant" sed 's/\[\[ -v MOSAIC_HOST_ROOT \]\] \&\& host_set=1/[[ -n "${MOSAIC_HOST_ROOT:-}" ]] \&\& host_set=1/; s/\[\[ -v MOSAIC_BRAIN_HOME \]\] \&\& brain_set=1/[[ -n "${MOSAIC_BRAIN_HOME:-}" ]] \&\& brain_set=1/' \ "$DOCTOR" > "$MUT" if cmp -s "$DOCTOR" "$MUT"; then echo "SKIP red control (mutation anchor not found — sed pattern drifted)" >&2 else mut_fn=$(sed -n "/^check_structure_anchor_provisioning() {/,/^}/p" "$MUT") outm=$(env MOSAIC_HOST_ROOT= MOSAIC_BRAIN_HOME= bash -c \ "warn() { echo \"[WARN] \$*\"; }; note() { echo \"[NOTE] \$*\"; return 0; }; pass() { echo \"[OK] \$*\"; return 0; }; $mut_fn; check_structure_anchor_provisioning" 2>&1) if printf '%s\n' "$outm" | grep -q '^\[NOTE\]'; then echo "ok - red control bites (mutant collapses empty into informational; shipped does not)" else fail "red control did not reproduce the regression shape (mutant output unexpected)" fi fi echo "structure anchor doctor check: all arms passed"