fix(framework): track anchor presence separately from value (T51 WP0b rework)
ci/woodpecker/pr/ci Pipeline was successful
ci/woodpecker/pr/ci Pipeline was successful
${VAR:-} collapsed exported-empty into genuinely-unset, mis-filing
both-empty and the two mixed empty/unset states as informational where
the charter requires WARNs. Presence now tracked via [[ -v VAR ]]
alongside value: NOTES only when both variables are genuinely absent;
any present-but-empty or single-present state emits a loud WARN per
missing/empty anchor, each naming the launchers as authority (unset and
empty get distinct wording). Suite: the wrong both-empty note arm
replaced by three warn arms (both-empty, host-empty+brain-unset,
host-unset+brain-empty); warn arms accept >=1 warn with zero notes
(single-present states warn once, both-present-empty warns twice — per
anchor, by design); red control now mutates presence tracking back to
the nonemptiness collapse (the reviewed defect shape) and must emit
NOTEs for both-empty. 10 arms green; gates green.
This commit is contained in:
@@ -392,19 +392,34 @@ check_structure_anchor_provisioning() {
|
|||||||
# Severity follows the doctor's existing conventions: pass/note are quiet
|
# Severity follows the doctor's existing conventions: pass/note are quiet
|
||||||
# (note unless --verbose), warn counts toward --fail-on-warn.
|
# (note unless --verbose), warn counts toward --fail-on-warn.
|
||||||
local host_root="${MOSAIC_HOST_ROOT:-}" brain_home="${MOSAIC_BRAIN_HOME:-}"
|
local host_root="${MOSAIC_HOST_ROOT:-}" brain_home="${MOSAIC_BRAIN_HOME:-}"
|
||||||
if [[ -n "$host_root" && -n "$brain_home" ]]; then
|
# T51P2WP0BRW B1: presence is tracked SEPARATELY from value — `${VAR:-}`
|
||||||
|
# collapses exported-empty into genuinely-unset, which mis-filed both-empty
|
||||||
|
# and the mixed empty/unset states as informational. Only BOTH-genuinely-
|
||||||
|
# absent may be informational (charter state 3); any present-but-empty or
|
||||||
|
# single-present state warns.
|
||||||
|
local host_set=0 brain_set=0
|
||||||
|
[[ -v MOSAIC_HOST_ROOT ]] && host_set=1
|
||||||
|
[[ -v MOSAIC_BRAIN_HOME ]] && brain_set=1
|
||||||
|
if [[ "$host_set" -eq 1 && "$brain_set" -eq 1 && -n "$host_root" && -n "$brain_home" ]]; then
|
||||||
pass "Structure anchors provisioned: MOSAIC_HOST_ROOT=$host_root MOSAIC_BRAIN_HOME=$brain_home (paths reported only; not expanded, not consumed)"
|
pass "Structure anchors provisioned: MOSAIC_HOST_ROOT=$host_root MOSAIC_BRAIN_HOME=$brain_home (paths reported only; not expanded, not consumed)"
|
||||||
return
|
return
|
||||||
fi
|
fi
|
||||||
if [[ -z "$host_root" && -z "$brain_home" ]]; then
|
if [[ "$host_set" -eq 0 && "$brain_set" -eq 0 ]]; then
|
||||||
note "Structure anchors not provisioned in this environment. Launcher-equivalent derivation (INFORMATIONAL, NON-AUTHORITATIVE — seats receive the authoritative values from the launchers): MOSAIC_HOST_ROOT would default to the operator home; MOSAIC_BRAIN_HOME would default to the brain tree resolved at launch. Doctor does not guess values for consumption; it audits provisioning."
|
note "Structure anchors not provisioned in this environment. Launcher-equivalent derivation (INFORMATIONAL, NON-AUTHORITATIVE — seats receive the authoritative values from the launchers): MOSAIC_HOST_ROOT would default to the operator home; MOSAIC_BRAIN_HOME would default to the brain tree resolved at launch. Doctor does not guess values for consumption; it audits provisioning."
|
||||||
note "Provision both anchors via the seat launchers (launch-seat.sh / launch-seat-claude.sh export them; see T51 spec §1.2a)."
|
note "Provision both anchors via the seat launchers (launch-seat.sh / launch-seat-claude.sh export them; see T51 spec §1.2a)."
|
||||||
return
|
return
|
||||||
fi
|
fi
|
||||||
if [[ -z "$host_root" ]]; then
|
# At least one variable is present (possibly empty), or exactly one exists:
|
||||||
warn "MOSAIC_HOST_ROOT is missing or empty in this environment while MOSAIC_BRAIN_HOME is set — declaration consumers fail closed without it (spec §1.2a). The seat launchers are the authoritative source."
|
# every missing/empty anchor gets its own loud WARN naming the launchers.
|
||||||
else
|
if [[ "$host_set" -eq 0 ]]; then
|
||||||
warn "MOSAIC_BRAIN_HOME is missing or empty in this environment while MOSAIC_HOST_ROOT is set — the projects/ mirror and brain declaration resolve from it (spec §1.2a). The seat launchers are the authoritative source."
|
warn "MOSAIC_HOST_ROOT is not set in this environment while MOSAIC_BRAIN_HOME is — declaration consumers fail closed without it (spec §1.2a). The seat launchers are the authoritative source."
|
||||||
|
elif [[ -z "$host_root" ]]; then
|
||||||
|
warn "MOSAIC_HOST_ROOT is present but EMPTY in this environment — declaration consumers fail closed without a usable value (spec §1.2a). The seat launchers are the authoritative source."
|
||||||
|
fi
|
||||||
|
if [[ "$brain_set" -eq 0 ]]; then
|
||||||
|
warn "MOSAIC_BRAIN_HOME is not set in this environment while MOSAIC_HOST_ROOT is — the projects/ mirror and brain declaration resolve from it (spec §1.2a). The seat launchers are the authoritative source."
|
||||||
|
elif [[ -z "$brain_home" ]]; then
|
||||||
|
warn "MOSAIC_BRAIN_HOME is present but EMPTY in this environment — the projects/ mirror and brain declaration resolve from it (spec §1.2a). The seat launchers are the authoritative source."
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
# 1. both present+nonempty -> pass ([OK]), no warns, no notes
|
# 1. both present+nonempty -> pass ([OK]), no warns, no notes
|
||||||
# 2a. host missing, brain set -> warn naming MOSAIC_HOST_ROOT + launchers
|
# 2a. host missing, brain set -> warn naming MOSAIC_HOST_ROOT + launchers
|
||||||
# 2b. brain missing, host set -> warn naming MOSAIC_BRAIN_HOME + launchers
|
# 2b. brain missing, host set -> warn naming MOSAIC_BRAIN_HOME + launchers
|
||||||
# 2c. present-but-EMPTY counts as missing (both empty -> state 3; one empty -> state 2)
|
# 2c. present-but-EMPTY counts as missing (warns; NEVER informational)
|
||||||
# 3. neither present -> informational notes, NON-AUTHORITATIVE, never warn
|
# 3. neither present -> informational notes, NON-AUTHORITATIVE, never warn
|
||||||
# Arms include genuinely-UNSET (env -u) forms, not only empty strings.
|
# Arms include genuinely-UNSET (env -u) forms, not only empty strings.
|
||||||
# Red control: empty-vs-unset distinction removed in a mutated copy -> suite red.
|
# Red control: empty-vs-unset distinction removed in a mutated copy -> suite red.
|
||||||
@@ -64,8 +64,8 @@ run_case() {
|
|||||||
oks=$(printf '%s\n' "$out" | grep -c '^\[OK\]' || true)
|
oks=$(printf '%s\n' "$out" | grep -c '^\[OK\]' || true)
|
||||||
if [[ "$expect" == ok && "$oks" -gt 0 && "$warns" -eq 0 && "$notes" -eq 0 ]]; then
|
if [[ "$expect" == ok && "$oks" -gt 0 && "$warns" -eq 0 && "$notes" -eq 0 ]]; then
|
||||||
echo "ok - $label"
|
echo "ok - $label"
|
||||||
elif [[ "$expect" == warn && "$warns" -eq 1 ]]; then
|
elif [[ "$expect" == warn && "$warns" -ge 1 && "$notes" -eq 0 ]]; then
|
||||||
echo "ok - $label (warned)"
|
echo "ok - $label (warned x$warns)"
|
||||||
elif [[ "$expect" == note && "$notes" -gt 0 && "$warns" -eq 0 ]]; then
|
elif [[ "$expect" == note && "$notes" -gt 0 && "$warns" -eq 0 ]]; then
|
||||||
echo "ok - $label (noted)"
|
echo "ok - $label (noted)"
|
||||||
else
|
else
|
||||||
@@ -100,22 +100,29 @@ run_case "empty-string brain home warns (empty != set)" warn \
|
|||||||
# ── state 3: neither present (genuinely unset) → notes, never warn ─────────
|
# ── state 3: neither present (genuinely unset) → notes, never warn ─────────
|
||||||
run_case "both unset yields non-authoritative notes" note \
|
run_case "both unset yields non-authoritative notes" note \
|
||||||
-u:MOSAIC_HOST_ROOT -u:MOSAIC_BRAIN_HOME
|
-u:MOSAIC_HOST_ROOT -u:MOSAIC_BRAIN_HOME
|
||||||
run_case "both empty-string yields non-authoritative notes" note \
|
run_case "both empty-string warns (empty is present, not absent)" warn \
|
||||||
MOSAIC_HOST_ROOT= MOSAIC_BRAIN_HOME=
|
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): empty-vs-unset distinction removed → red ───────
|
# ── red control (mutation): presence tracking removed → red ────────────────
|
||||||
# Mutant replaces the -n tests with plain set-tests, so an EMPTY value counts
|
# Mutant regresses to the reviewed defect shape: presence derived from
|
||||||
# as present: the empty-host arm above would flip to pass and the suite reds.
|
# 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"
|
MUT="$ROOT/mosaic-doctor.mutant"
|
||||||
sed 's/\[\[ -n "$host_root" \&\& -n "$brain_home" \]\]/[[ -v MOSAIC_HOST_ROOT \&\& -v MOSAIC_BRAIN_HOME ]]/' \
|
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"
|
"$DOCTOR" > "$MUT"
|
||||||
if cmp -s "$DOCTOR" "$MUT"; then
|
if cmp -s "$DOCTOR" "$MUT"; then
|
||||||
echo "SKIP red control (mutation anchor not found — sed pattern drifted)" >&2
|
echo "SKIP red control (mutation anchor not found — sed pattern drifted)" >&2
|
||||||
else
|
else
|
||||||
outm=$(env MOSAIC_HOST_ROOT= MOSAIC_BRAIN_HOME="$BRAIN" bash -c \
|
mut_fn=$(sed -n "/^check_structure_anchor_provisioning() {/,/^}/p" "$MUT")
|
||||||
"warn() { echo \"[WARN] \$*\"; }; note() { echo \"[NOTE] \$*\"; return 0; }; pass() { echo \"[OK] \$*\"; return 0; }; $(sed -n "/^check_structure_anchor_provisioning() {/,/^}/p" "$MUT"); check_structure_anchor_provisioning" 2>&1)
|
outm=$(env MOSAIC_HOST_ROOT= MOSAIC_BRAIN_HOME= bash -c \
|
||||||
if printf '%s\n' "$outm" | grep -q '^\[OK\]'; then
|
"warn() { echo \"[WARN] \$*\"; }; note() { echo \"[NOTE] \$*\"; return 0; }; pass() { echo \"[OK] \$*\"; return 0; }; $mut_fn; check_structure_anchor_provisioning" 2>&1)
|
||||||
echo "ok - red control bites (mutant treats empty as present; shipped does not)"
|
if printf '%s\n' "$outm" | grep -q '^\[NOTE\]'; then
|
||||||
|
echo "ok - red control bites (mutant collapses empty into informational; shipped does not)"
|
||||||
else
|
else
|
||||||
fail "red control did not reproduce the regression shape (mutant output unexpected)"
|
fail "red control did not reproduce the regression shape (mutant output unexpected)"
|
||||||
fi
|
fi
|
||||||
|
|||||||
Reference in New Issue
Block a user