Files
stack/packages/mosaic/framework/tools/orchestrator/test-board-roll.sh
jason.woltje b79336a8c1
Some checks failed
ci/woodpecker/push/publish Pipeline was successful
ci/woodpecker/push/ci Pipeline failed
feat(orchestrator): board-roll.sh — auto-roll LIVE board to LEDGER under byte cap (#868)
feat(orchestrator): board-roll.sh - auto-roll LIVE board to LEDGER under byte cap

Closes #868
2026-07-22 09:20:03 +00:00

157 lines
7.9 KiB
Bash

#!/usr/bin/env bash
# Regression harness for board-roll.sh — rolling oldest LIVE-board entries to LEDGER.
#
# Asserts:
# 1. Under cap → no-op, exit 0, files unchanged.
# 2. Over cap, no roll markers → exit 3, LIVE unchanged (never guesses).
# 3. Over cap, markers present → rolls the fewest oldest entries to get under cap,
# LIVE ends under cap, pinned preamble/footer + newest entries preserved.
# 4. Rolled blocks land in the LEDGER verbatim, oldest set in original order.
# 5. --dry-run changes nothing and reports a plan.
# 6. Zone emptied but pinned sections alone exceed cap → exit 3.
# 7. --help exits 0 and prints usage; an unknown flag exits nonzero (#701 discipline).
# 8. More than one marker pair → exit 3, unchanged; curated content between the two
# zones is never relocated to the LEDGER (rev0 #868 regression).
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
SUT="$SCRIPT_DIR/board-roll.sh"
fail=0
note() { echo "FAIL: $*" >&2; fail=1; }
WORK="$(mktemp -d)"
trap 'rm -rf "$WORK"' EXIT
# builds a LIVE board: pinned preamble + roll zone with N dated entries (newest first),
# each entry padded to be individually large so the cap math is predictable.
make_board() { # $1 file $2 n_entries $3 with_markers(1/0) $4 pad_bytes
local f=$1 n=$2 markers=$3 pad=$4 i padtxt
padtxt=$(head -c "$pad" < /dev/zero | tr '\0' 'x')
{
echo "# BOARD — LIVE"
echo "> pinned protocol blockquote, never rolled."
echo
echo "## Curated always-current section (pinned)"
echo "- this stays no matter what"
echo
[[ "$markers" == 1 ]] && echo '<!-- BOARD-ROLL:START -->'
# newest first (i=n .. 1); oldest (i=1) ends at the bottom
for (( i=n; i>=1; i-- )); do
echo "### 2026-07-$(printf '%02d' $i) tick number $i"
echo "- detail $i $padtxt"
echo
done
[[ "$markers" == 1 ]] && echo '<!-- BOARD-ROLL:END -->'
} > "$f"
return 0
}
# ── 1. under cap → no-op ───────────────────────────────────────────────────────
L="$WORK/live1.md"; G="$WORK/ledger1.md"; : > "$G"
make_board "$L" 2 1 10
before=$(cat "$L")
if ! out=$(bash "$SUT" --live "$L" --ledger "$G" --cap 100000 2>&1); then
note "under-cap should exit 0 (got nonzero): $out"
fi
[[ "$(cat "$L")" == "$before" ]] || note "under-cap modified LIVE"
[[ -s "$G" ]] && note "under-cap wrote to LEDGER"
# ── 2. over cap, no markers → exit 3, unchanged ────────────────────────────────
L="$WORK/live2.md"; G="$WORK/ledger2.md"; : > "$G"
make_board "$L" 6 0 400
before=$(cat "$L")
set +e; bash "$SUT" --live "$L" --ledger "$G" --cap 800 >/dev/null 2>&1; rc=$?; set -e
[[ "$rc" -eq 3 ]] || note "no-markers over-cap should exit 3 (got $rc)"
[[ "$(cat "$L")" == "$before" ]] || note "no-markers run modified LIVE (must never guess)"
# ── 3+4. over cap with markers → rolls oldest, LIVE under cap, LEDGER gets them ─
L="$WORK/live3.md"; G="$WORK/ledger3.md"; echo "# LEDGER" > "$G"
make_board "$L" 6 1 400 # 6 entries, each ~>400B
big=$(wc -c < "$L")
[[ "$big" -ge 2000 ]] || note "fixture too small to test rolling ($big B)"
if ! out=$(bash "$SUT" --live "$L" --ledger "$G" --cap 2000 2>&1); then
note "marker roll should exit 0 when it can get under cap: $out"
fi
after=$(wc -c < "$L")
[[ "$after" -lt 2000 ]] || note "LIVE still >= cap after roll ($after B)"
# pinned content survives
grep -q "Curated always-current section" "$L" || note "roll dropped pinned section"
grep -q 'BOARD-ROLL:START' "$L" || note "roll dropped START marker"
grep -q 'BOARD-ROLL:END' "$L" || note "roll dropped END marker"
# newest entry (07-06) stays; oldest (07-01) is the first to leave
grep -q "### 2026-07-06 tick number 6" "$L" || note "roll dropped the newest entry"
grep -q "### 2026-07-01 tick number 1" "$L" && note "oldest entry not rolled out of LIVE"
# oldest went to LEDGER
grep -q "### 2026-07-01 tick number 1" "$G" || note "oldest entry not appended to LEDGER"
grep -q "board-roll:.*rolled from live3.md" "$G" || note "LEDGER missing provenance separator"
# a rolled entry must not be duplicated (present in exactly one of LIVE/LEDGER)
if grep -q "### 2026-07-01 tick number 1" "$L"; then note "rolled entry duplicated in LIVE"; fi
# LEDGER original content preserved
grep -q "^# LEDGER" "$G" || note "roll clobbered existing LEDGER content"
# ── 5. --dry-run changes nothing ───────────────────────────────────────────────
L="$WORK/live5.md"; G="$WORK/ledger5.md"; echo "# LEDGER" > "$G"
make_board "$L" 6 1 400
before_l=$(cat "$L"); before_g=$(cat "$G")
out=$(bash "$SUT" --live "$L" --ledger "$G" --cap 2000 --dry-run 2>&1) || note "dry-run exited nonzero: $out"
echo "$out" | grep -qi "dry run" || note "dry-run did not announce itself"
echo "$out" | grep -q "would roll" || note "dry-run did not report a plan"
[[ "$(cat "$L")" == "$before_l" ]] || note "dry-run modified LIVE"
[[ "$(cat "$G")" == "$before_g" ]] || note "dry-run modified LEDGER"
# ── 6. zone emptied, pinned alone over cap → exit 3 ────────────────────────────
# cap 120 is below the pinned preamble+footer size (~180B), so even after rolling
# every zone entry the LIVE file stays over cap → must report the unsatisfiable case.
L="$WORK/live6.md"; G="$WORK/ledger6.md"; echo "# LEDGER" > "$G"
make_board "$L" 3 1 50
set +e; bash "$SUT" --live "$L" --ledger "$G" --cap 120 >/dev/null 2>&1; rc=$?; set -e
[[ "$rc" -eq 3 ]] || note "unsatisfiable cap should exit 3 (got $rc)"
# ── 7. help exits 0, unknown flag exits nonzero (#701) ─────────────────────────
if ! out=$(bash "$SUT" --help 2>&1); then note "--help exited nonzero"; fi
[[ "$out" == Usage:* ]] || note "--help did not print usage"
bash "$SUT" -h >/dev/null 2>&1 || note "-h exited nonzero"
if bash "$SUT" --not-a-real-flag >/dev/null 2>&1; then note "unknown flag was accepted"; fi
if bash "$SUT" --live "$WORK/live3.md" >/dev/null 2>&1; then note "missing --ledger was accepted"; fi
# ── 8. multiple marker pairs → exit 3, unchanged (no cross-zone relocation) ─────
# Two separately-marked zones with a curated pinned section BETWEEN them. A naive
# first-START..last-END span would sweep that curated section (and the intermediate
# markers) into the LEDGER. board-roll must refuse (exit 3) and touch nothing.
L="$WORK/live8.md"; G="$WORK/ledger8.md"; echo "# LEDGER" > "$G"
pad8=$(head -c 300 < /dev/zero | tr '\0' 'x')
{
echo "# BOARD — LIVE"
echo "> pinned protocol blockquote"
echo
echo '<!-- BOARD-ROLL:START -->'
echo "### 2026-07-10 zone-A newest"
echo "- detail A2 $pad8"
echo "### 2026-07-09 zone-A oldest"
echo "- detail A1 $pad8"
echo '<!-- BOARD-ROLL:END -->'
echo
echo "## Curated-between-zones (pinned — must never move)"
echo "- CANARY-BETWEEN keep me"
echo
echo '<!-- BOARD-ROLL:START -->'
echo "### 2026-07-08 zone-B newest"
echo "- detail B2 $pad8"
echo "### 2026-07-07 zone-B oldest"
echo "- detail B1 $pad8"
echo '<!-- BOARD-ROLL:END -->'
} > "$L"
before8=$(cat "$L")
set +e; bash "$SUT" --live "$L" --ledger "$G" --cap 80 >/dev/null 2>&1; rc=$?; set -e
[[ "$rc" -eq 3 ]] || note "multi-pair board should exit 3 (got $rc)"
[[ "$(cat "$L")" == "$before8" ]] || note "multi-pair run modified LIVE (must never guess across zones)"
grep -q "CANARY-BETWEEN keep me" "$L" || note "multi-pair run relocated curated between-zones content"
grep -q "CANARY-BETWEEN" "$G" && note "curated between-zones content leaked into LEDGER"
if [[ "$fail" -eq 0 ]]; then
echo "board-roll regression passed (8 groups)"
fi
exit "$fail"