Files
boshu2__agentops/scripts/check-dream-throughput.sh
T
Claude 41c71f54d6 feat(nightly): fail loudly on dream close-loop throughput stalls
The 2026-04-22 nightly-dream-cycle learning
(.agents/learnings/2026-04-22-close-loop-citation-gate-deadlock.md) lists
three corrective actions for the chicken-and-egg promotion deadlock that
silently zeroed throughput for weeks:

  1. Split admission gates by path                        — DONE (b69a00f)
  2. Parameterize shared helpers (requireCitations bool)  — DONE (b69a00f)
  3. Fail loudly if ingested > 0 && promoted == 0         — this commit

Prior to this commit, scripts/nightly-dream-cycle.sh reported both numbers
in the summary but never asserted their relationship, so the deadlock
surfaced only in downstream metrics (sigma=0, escape_velocity=false) —
exactly the "quietly posting another zero-throughput status issue" pattern
the learning warns against.

Changes:

- scripts/check-dream-throughput.sh (new): standalone gate consuming
  'ao flywheel close-loop --json'. Exits 1 on the deadlock pattern
  (added > 0 && promoted == 0), 0 on healthy / no-op, 2 on bad input.
  Uses the same pattern as the sibling check-compile-*.sh gates.
- scripts/nightly-dream-cycle.sh: invokes the gate after the summary
  artifacts are written (so uploads still succeed) and exits non-zero
  when a stall is detected. NIGHTLY_DREAM_STRICT=0 downgrades to warn
  for diagnostic runs. The summary.json grows a
  close_loop.throughput_stalled bool; the summary.md renders a banner
  above the stage table when the stall fires, so the auto-filed
  "Nightly dream cycle status" issue leads with it.
- tests/scripts/check-dream-throughput.bats (new): 8 cases covering
  healthy, empty-run, deadlock, missing input, no-arg, non-integer
  input, and missing keys.

Verified locally against all 8 cases via direct bash invocation
(bats is not available in this environment); shell syntax validated
with 'bash -n' on both scripts.
2026-04-22 11:43:15 +00:00

60 lines
1.9 KiB
Bash
Executable File

#!/usr/bin/env bash
# check-dream-throughput.sh — Gate: dream-cycle close-loop pipeline produced
# non-zero throughput for the candidates it ingested.
#
# Guards against the chicken-and-egg gate deadlock documented in
# .agents/learnings/2026-04-22-close-loop-citation-gate-deadlock.md: when
# fresh candidates were ingested but none reached auto-promotion, the pipeline
# is stalled regardless of how "clean" each stage looks in isolation.
#
# Consumes the JSON shape emitted by `ao flywheel close-loop --json`:
# {"ingest":{"added":N},"auto_promote":{"promoted":M}}
#
# Exit codes:
# 0 PASS — either no ingest this run, or promoted > 0
# 1 FAIL — ingest.added > 0 && auto_promote.promoted == 0 (stall)
# 2 ERROR — missing/invalid input
#
# Usage: check-dream-throughput.sh <close-loop.json>
set -euo pipefail
INPUT="${1:-}"
if [[ -z "$INPUT" ]]; then
echo "usage: $0 <close-loop.json>" >&2
exit 2
fi
if [[ ! -f "$INPUT" ]]; then
echo "ERROR: $INPUT not found" >&2
exit 2
fi
if ! command -v jq >/dev/null 2>&1; then
echo "ERROR: jq not found" >&2
exit 2
fi
added="$(jq -r '.ingest.added // 0' "$INPUT" 2>/dev/null || echo "")"
promoted="$(jq -r '.auto_promote.promoted // 0' "$INPUT" 2>/dev/null || echo "")"
if ! [[ "$added" =~ ^[0-9]+$ ]] || ! [[ "$promoted" =~ ^[0-9]+$ ]]; then
echo "ERROR: could not parse .ingest.added / .auto_promote.promoted as integers in $INPUT" >&2
exit 2
fi
if (( added > 0 && promoted == 0 )); then
cat >&2 <<EOF
FAIL: dream close-loop throughput stall
ingest.added=$added but auto_promote.promoted=0
A nonzero ingest with zero promotions is a deadlocked pipeline, not a
steady state. See .agents/learnings/2026-04-22-close-loop-citation-gate-deadlock.md.
EOF
exit 1
fi
if (( added == 0 )); then
echo "OK: no candidates ingested this run (ingest.added=0); nothing to promote"
exit 0
fi
echo "PASS: auto_promote.promoted=$promoted / ingest.added=$added"
exit 0