Files
boshu2__agentops/scripts/update-cli-surface-counts.sh
Bo 81e6380510 feat(cli): wire ao eval — the Learn seat's measurement surface (#921)
Registers the fully-built-but-never-wired eval module into the CLI spine
and repairs its one real instrument bug. Three commits, RPI-shaped: wire
+ fix, drift guards + docs, fixture counts.

## What
- **`ao eval` joins the spine** (cmd/ao/eval_composition.go):
deterministic suite runs, run-record
compare/baseline/scorecard/coverage, locked Tasks, holdout scenarios,
suite A/B verdicts with power-derived n-required, and the holdout-safe
Outcomes projection. This is the operating contract's *Learn* seat — a
read/measure consumer of evidence. It reports numbers and owns no retry,
scheduling, promotion, or lifecycle authority. The retired Aliases/Bench
seats stay nil and their subcommands are omitted.
- **Instrument bug fixed**: both scenario-ab arms were corpus-denied at
runtime — the with-gold treatment was only a prompt injection through
the retired `ao lookup`, so the A/B silently guaranteed a zero delta.
Treatment is now environment-shaped: the with-gold arm runs with the
corpus readable, the control arm stays sandbox-confined (the fail-closed
empty-deny guard is untouched), and judges are always corpus-denied.
- **Schema drift guards**: a run record persisted by the production
writer must validate against eval-run.v1.schema.json (and the minimal
suite against eval-suite.v1.schema.json) — closing the same silent-fork
class the verdict.v2 golden corpus closed.
- **Hermetic test builds hardened**: keep the real HOME's Go caches
(TestMain isolation was forcing module re-downloads) and skip VCS
stamping.
- docs/architecture/go-cli.md gains the eval section; MIGRATION.md notes
`ao eval`'s return; COMMANDS.md, cli-surface, and surface counts
regenerated; new leaves carry honest allowlist reasons; new cmd/ao L2
tests drive eval run/compare/help through the full production wiring.

## Evidence
- Full cli suite 2,801 green; race green on cmd/ao + the eval island;
vet clean
- Full-tier gate: 65/66 on the penultimate commit; the single failure
(surface counts) is the final fixture commit, re-verified PASS
standalone — no other check reads those fixtures
- Fresh independent validation (Codex, frozen subject 86022a3c6, clean
tree at start and end): **OVERALL PASS**, 6/6 — including a live
end-to-end `ao eval run` producing a passing run record
- Rubric-relocation decision honored: true holdout rubrics live in the
external measurement register; the repo keeps only leak-guarded
projections
2026-07-18 18:33:46 -04:00

102 lines
4.3 KiB
Bash
Executable File

#!/usr/bin/env bash
set -euo pipefail
# Synchronize the hard-coded CLI heading counts in the smoke script and
# canary matrix JSON with the actual counts in cli/docs/COMMANDS.md.
#
# Usage:
# scripts/update-cli-surface-counts.sh # Check; exit 1 if drifted
# scripts/update-cli-surface-counts.sh --fix # Rewrite counts in-place
FIX=false
if [[ "${1:-}" == "--fix" ]]; then
FIX=true
fi
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
COMMANDS_PATH="$REPO_ROOT/cli/docs/COMMANDS.md"
SMOKE_PATH="$REPO_ROOT/evals/agentops-core/fixtures/cli-command-surface-smoke.sh"
MATRIX_PATH="$REPO_ROOT/evals/agentops-core/cli-command-surface-matrix.json"
errors=0
fail() {
printf 'CLI_SURFACE_COUNTS: FAIL %s\n' "$*" >&2
errors=$((errors + 1))
}
if [[ ! -f "$COMMANDS_PATH" ]]; then
fail "COMMANDS.md not found: $COMMANDS_PATH"
exit 1
fi
actual_top="$(grep -Ec '^### `ao ' "$COMMANDS_PATH" || true)"
actual_sub="$(grep -Ec '^#### `ao ' "$COMMANDS_PATH" || true)"
# all spans every command heading depth (###..#####); eval task/suite/scenario
# children are the first three-level-deep commands (##### headings). Keep in
# lockstep with scripts/regen-command-surfaces.sh.
actual_all="$(grep -Ec '^#{3,5} `ao ' "$COMMANDS_PATH" || true)"
smoke_line="$(grep -E '^\s*if \[\[ "\$top_count"' "$SMOKE_PATH" 2>/dev/null || true)"
smoke_top="$(echo "$smoke_line" | sed -nE 's/.*"\$top_count" != "([0-9]+)".*/\1/p')"
smoke_sub="$(echo "$smoke_line" | sed -nE 's/.*"\$sub_count" != "([0-9]+)".*/\1/p')"
smoke_all="$(echo "$smoke_line" | sed -nE 's/.*"\$all_count" != "([0-9]+)".*/\1/p')"
smoke_array_line="$(grep -E '^\s*if \[\[ "\$\{#commands' "$SMOKE_PATH" 2>/dev/null || true)"
smoke_array_count="$(echo "$smoke_array_line" | sed -nE 's/.*-ne ([0-9]+).*/\1/p')"
matrix_line="$(grep -o 'cli-command-headings: top=[0-9]* sub=[0-9]* all=[0-9]*' "$MATRIX_PATH" 2>/dev/null || true)"
matrix_top="$(echo "$matrix_line" | sed -nE 's/.*top=([0-9]+).*/\1/p')"
matrix_sub="$(echo "$matrix_line" | sed -nE 's/.*sub=([0-9]+).*/\1/p')"
matrix_all="$(echo "$matrix_line" | sed -nE 's/.*all=([0-9]+).*/\1/p')"
smoke_drifted=false
if [[ "$smoke_top" != "$actual_top" || "$smoke_sub" != "$actual_sub" || "$smoke_all" != "$actual_all" ]]; then
smoke_drifted=true
fi
if [[ -n "$smoke_array_count" && "$smoke_array_count" != "$actual_all" ]]; then
smoke_drifted=true
fi
if $smoke_drifted; then
if $FIX; then
new_assert="if [[ \"\$top_count\" != \"$actual_top\" || \"\$sub_count\" != \"$actual_sub\" || \"\$all_count\" != \"$actual_all\" ]]; then"
old_assert="if [[ \"\$top_count\" != \"$smoke_top\" || \"\$sub_count\" != \"$smoke_sub\" || \"\$all_count\" != \"${smoke_all:-$actual_all}\" ]]; then"
tmp="$(mktemp)"
awk -v old="$old_assert" -v new="$new_assert" \
-v old_ne="${smoke_array_count:-$actual_all}" -v new_ne="$actual_all" \
'{
if ($0 ~ /top_count.*!=.*sub_count.*!=.*all_count/) { print new }
else if ($0 ~ /-ne [0-9]+/) { gsub("-ne " old_ne, "-ne " new_ne); print }
else { print }
}' "$SMOKE_PATH" > "$tmp"
mv "$tmp" "$SMOKE_PATH"
chmod +x "$SMOKE_PATH"
printf 'CLI_SURFACE_COUNTS: --fix updated smoke script -> top=%s sub=%s all=%s\n' \
"$actual_top" "$actual_sub" "$actual_all"
else
fail "smoke script counts drifted: expected top=$actual_top sub=$actual_sub all=$actual_all, got top=$smoke_top sub=$smoke_sub all=${smoke_all:-?}"
fi
fi
if [[ "$matrix_top" != "$actual_top" || "$matrix_sub" != "$actual_sub" || "$matrix_all" != "$actual_all" ]]; then
if $FIX; then
tmp="$(mktemp)"
sed "s/cli-command-headings: top=$matrix_top sub=$matrix_sub all=$matrix_all/cli-command-headings: top=$actual_top sub=$actual_sub all=$actual_all/" \
"$MATRIX_PATH" > "$tmp"
mv "$tmp" "$MATRIX_PATH"
printf 'CLI_SURFACE_COUNTS: --fix updated matrix JSON -> top=%s sub=%s all=%s\n' \
"$actual_top" "$actual_sub" "$actual_all"
else
fail "matrix JSON counts drifted: expected top=$actual_top sub=$actual_sub all=$actual_all, got top=$matrix_top sub=$matrix_sub all=$matrix_all"
fi
fi
if [[ "$errors" -gt 0 ]]; then
printf 'CLI_SURFACE_COUNTS: %d drift(s) detected. Run with --fix to update.\n' "$errors" >&2
exit 1
fi
printf 'CLI_SURFACE_COUNTS: PASS (top=%s sub=%s all=%s)\n' "$actual_top" "$actual_sub" "$actual_all"