Ctrl K
ComunidadGuías…

scripts/butler-b9-weekly-learning.sh

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
#!/usr/bin/env bash
# B9 weekly learning loop — export, Tier-1 LIVE gate, Tier-2 probe, SWE subset, lessons.
#
# Usage:
#   bash scripts/butler-b9-weekly-learning.sh
#   bash scripts/butler-b9-weekly-learning.sh minimax/MiniMax-M3
# Cron example (weekly Sunday 03:00):
#   0 3 * * 0 cd /path/to/WFXM && bash scripts/butler-b9-weekly-learning.sh >> /tmp/b9-weekly.log 2>&1
set -euo pipefail

ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
cd "$ROOT"
export PYTHONPATH="$ROOT"
export BUTLER_EVAL_LLM_BENCHMARK=1

MODEL="${1:-minimax/MiniMax-M3}"

if [[ -f "$ROOT/.env" ]]; then
  set -a
  # shellcheck disable=SC1091
  source "$ROOT/.env" 2>/dev/null || true
  set +a
fi

echo "=== B9 weekly: export Tier-1 curriculum ==="
bash "$ROOT/scripts/butler-b9-export-curriculum.sh" --tier1-only

echo ""
echo "=== B9 weekly: Tier-1 LIVE model=$MODEL ==="
bash "$ROOT/scripts/butler-eval-b9-probe-model.sh" --tier1 "$MODEL"

echo ""
echo "=== B9 weekly: Tier-2 probe (conditional gate) ==="
TIER2_GATE_ENABLED="${BUTLER_B9_TIER2_GATE_ENABLED:-1}"
TIER2_MIN="${BUTLER_B9_TIER2_GATE_MIN_PASSED:-2}"
if bash "$ROOT/scripts/butler-eval-b9-probe-model.sh" "$MODEL"; then
  echo "Tier-2 probe: gate passed (enabled=${TIER2_GATE_ENABLED}, min=${TIER2_MIN})"
else
  if [[ "$TIER2_GATE_ENABLED" == "1" ]]; then
    echo "B9 TIER2 PROBE GATE: FAILED (need >=${TIER2_MIN}/3)" >&2
    exit 1
  fi
  echo "(tier2 probe had failures — stretch only; BUTLER_B9_TIER2_GATE_ENABLED=0)"
fi

echo ""
echo "=== B9 weekly: SWE-bench subset (non-blocking) ==="
bash "$ROOT/scripts/butler-eval-swebench-live.sh" || echo "(SWE weekly subset had failures)"

echo ""
echo "=== B9 weekly: lesson summary ==="
python3 - <<'PY'
import json
from collections import Counter
from pathlib import Path

from butler.ops.b9_lessons import b9_lessons_path

p = b9_lessons_path()
if not p.is_file():
    print("(no lessons yet)")
    raise SystemExit(0)
rows = []
for line in p.read_text(encoding="utf-8").splitlines():
    if line.strip():
        rows.append(json.loads(line))
kinds = Counter(r.get("kind") for r in rows)
classes = Counter(r.get("classification") for r in rows)
print(f"lessons_total={len(rows)} kinds={dict(kinds)} classifications={dict(classes)}")
print(f"path={p}")

from butler.ops.b9_harness_audit import (
    format_harness_friction_delta,
    format_harness_friction_report,
    record_harness_friction_snapshot,
)

print()
snap = record_harness_friction_snapshot()
print(format_harness_friction_report(snap))
print(format_harness_friction_delta(snap.get("delta")))
PY

echo ""
echo "=== B9 weekly: production delegate quality snapshot ==="
python3 - <<'PY'
from butler.dev_engine.b9_experience_retrieval import backfill_b9_experience_retrieval
from butler.ops.b9_prod_weekly import (
    format_production_delegate_delta,
    format_production_delegate_report,
    record_production_delegate_snapshot,
)

backfill = backfill_b9_experience_retrieval()
snap = record_production_delegate_snapshot()
print(format_production_delegate_report(snap))
print(format_production_delegate_delta(snap.get("delta")))
clean = snap.get("clean") or {}
print(format_production_delegate_report(clean, clean=True))
print(format_production_delegate_delta(snap.get("clean_delta"), clean=True))
print(f"b9_experience_backfill_updated={backfill.get('updated', 0)}")
from butler.ops.lingwen1_capture_probe import run_lingwen1_capture_probe
from butler.ops.lingwen1_failure_seed import seed_lingwen1_failure_audit
from butler.ops.b9_prod_promoted_registry import LINGWEN1_CAPTURE_NOTE
from butler.ops.experience_selection_telemetry import (
    backfill_selection_task_affinity,
    summarize_experience_lifecycle,
    summarize_experience_selections,
    summarize_selection_precision,
    replay_selection_precision,
    forward_selection_precision,
)

print("lingwen1_seed=", seed_lingwen1_failure_audit())
print("lingwen1_capture_probe=", run_lingwen1_capture_probe())
print(f"lingwen1_note={LINGWEN1_CAPTURE_NOTE}")
bf = backfill_selection_task_affinity(dry_run=False)
print(f"experience_affinity_backfill={bf}")
print("experience_selections=", summarize_experience_selections())
print("experience_selection_precision=", summarize_selection_precision())
print("experience_selection_replay=", replay_selection_precision())
print("experience_selection_forward=", forward_selection_precision())
print("experience_lifecycle=", summarize_experience_lifecycle())
from butler.ops.prod_experience_effectiveness import format_prod_experience_effectiveness

print()
print(format_prod_experience_effectiveness())
PY

echo ""
echo "=== B9 weekly: promoted prod LIVE probe (phase C, non-blocking) ==="
PROMOTED_RC=0
python3 - <<'PY' || PROMOTED_RC=$?
import json, sys
from butler.ops.b9_prod_weekly import run_promoted_prod_live_probe

probe = run_promoted_prod_live_probe()
layers = probe.get("layers") or {}
core = layers.get("core") or {}
stretch = layers.get("stretch") or {}
print(json.dumps(probe, ensure_ascii=False, indent=2))
print(
    f"\nPromoted prod core ({probe.get('mode')}): "
    f"{core.get('passed', probe.get('passed'))}/{core.get('total', probe.get('total'))}"
)
if stretch.get("total"):
    print(f"Promoted prod stretch ({probe.get('mode')}): {stretch.get('passed')}/{stretch.get('total')}")
if not probe.get("core_gate_ok", True):
    print("PROMOTED PROD CORE: had failures", file=sys.stderr)
    raise SystemExit(1)
if stretch.get("total") and stretch.get("passed", 0) < stretch.get("total", 0):
    print("PROMOTED PROD STRETCH: had failures (non-blocking)", file=sys.stderr)
PY
if [ "${PROMOTED_RC:-0}" -ne 0 ]; then
  echo "(promoted prod core probe had failures — see stderr)"
fi

echo ""
echo "=== B9 weekly: LingWen1 prod sample (phase C, non-blocking) ==="
bash "$ROOT/scripts/butler-lingwen1-prod-sample.sh" 2>&1 || echo "(lingwen prod sample had failures — stretch only)"

echo ""
echo "=== B9 weekly: promotion queue sync + bundle ==="
python3 - <<'PY'
import json

from butler.ops.b9_prod_weekly import promote_latest_production_failure
from butler.ops.delegate_failure_b9_promote import (
    dismiss_spurious_promotion_queue_items,
    export_promotion_bundle,
    promotion_queue_summary,
    sync_promotion_queue_with_tasks,
)

dismissed = dismiss_spurious_promotion_queue_items()
synced = sync_promotion_queue_with_tasks()
promote = promote_latest_production_failure()
bundle = export_promotion_bundle(audit_limit=20)
summary = promotion_queue_summary()
print(
    json.dumps(
        {
            "promotion_dismissed": dismissed.get("dismissed", 0),
            "promotion_synced": synced.get("synced", 0),
            "production_promoted": promote.get("promoted", False),
            "production_promote_reason": promote.get("reason", ""),
            "queue_pending": summary.get("pending", 0),
            "candidates_path": bundle.get("candidates_path"),
            "queue_summary_path": bundle.get("queue_summary_path"),
        },
        ensure_ascii=False,
        indent=2,
    )
)
PY