mirror of
https://github.com/boshu2/agentops.git
synced 2026-09-14 15:08:13 +08:00
fcacbed3f9
## Summary Child arc of `soc-l4n8` (drift surfaced during #348). Mechanical cleanup of 6 pre-existing shellcheck warnings in scripts I did not previously touch — all SC2034 unused-vars, SC2088 intended-literal, SC2089/SC2090 template-string, SC2221/SC2222 redundant-case. Per anti-pattern #2 (no bundling pre-existing fixes), filed as an atomic side-quest off the #348 `soc-1lp1` PR rather than bundled into it. Closes: soc-j026 Discovered-from: soc-l4n8 ## Diff | File | Fix | |---|---| | `validate-codex-api-conformance.sh:59` | SC2088 disable directive — grep is intentionally matching the literal documented path | | `goal-failure-taxonomy.sh:30` | Trim redundant case patterns (`*toolchain-security*`, `*release-security*`, `*ci-security*` all already matched by `*security*`) | | `purge-global-garbage.sh:24` | Remove unused `bodylen` | | `nightly-pr-digest.sh:316` | Remove unused `landing_policy` (local + assignment) | | `add-validate-job.sh` | File-level SC2089/SC2090 disable for the template-string section | | `check-skill-size.sh:34` | Remove unused `name` | ## Validation - `shellcheck -S warning` clean on all 6 files. - `scripts/ship.sh` routes to `--fast` (no inventory touched). - Pre-push gate (fast): PASSED, 31 skipped, 1 advisory WARN (executable-spec, unrelated). Bounded-context: BC0-foundations (scripts) Evidence: `shellcheck -S warning scripts/*` (clean for the 6 files) Co-authored-by: Codex <codex@example.invalid>
432 lines
15 KiB
Bash
Executable File
432 lines
15 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
usage() {
|
|
cat <<'EOF'
|
|
nightly-pr-digest.sh
|
|
|
|
Generate a structured PR body from nightly evolution run state.
|
|
|
|
Reads the most recent nightly run directory and produces a markdown PR body
|
|
covering: baseline/final goals, cycle history, runtime-artifact flips, open PR
|
|
overlap, tracker degradation, transient flakes, auto-reverts, and tag-push
|
|
status.
|
|
|
|
Options:
|
|
--run-dir <path> Explicit nightly run directory (default: latest under .agents/nightly/)
|
|
--repo-root <path> Repository root (default: git top-level or cwd)
|
|
--branch <name> Branch name for the PR (default: read from run digest.json)
|
|
--output <path> Output file for PR body markdown (default: stdout)
|
|
--baseline-label <slug> Baseline label to compare against (default: latest)
|
|
--since <date> Git log start date for auto-revert scan (default: 24h ago)
|
|
--format <fmt> Output format: markdown|json (default: markdown)
|
|
-h, --help Show this help
|
|
EOF
|
|
}
|
|
|
|
die() { echo "nightly-pr-digest: $*" >&2; exit 1; }
|
|
log() { printf '[%s] %s\n' "$(date -u +%Y-%m-%dT%H:%M:%SZ)" "$*" >&2; }
|
|
|
|
RUN_DIR=""
|
|
REPO_ROOT=""
|
|
BRANCH=""
|
|
OUTPUT=""
|
|
BASELINE_LABEL=""
|
|
SINCE=""
|
|
FORMAT="markdown"
|
|
|
|
while [[ $# -gt 0 ]]; do
|
|
case "$1" in
|
|
--run-dir) RUN_DIR="${2:-}"; shift 2 ;;
|
|
--repo-root) REPO_ROOT="${2:-}"; shift 2 ;;
|
|
--branch) BRANCH="${2:-}"; shift 2 ;;
|
|
--output) OUTPUT="${2:-}"; shift 2 ;;
|
|
--baseline-label) BASELINE_LABEL="${2:-}"; shift 2 ;;
|
|
--since) SINCE="${2:-}"; shift 2 ;;
|
|
--format) FORMAT="${2:-}"; shift 2 ;;
|
|
-h|--help) usage; exit 0 ;;
|
|
*) die "unknown arg: $1" ;;
|
|
esac
|
|
done
|
|
|
|
if [[ -z "$REPO_ROOT" ]]; then
|
|
REPO_ROOT="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
|
|
fi
|
|
cd "$REPO_ROOT"
|
|
|
|
if [[ -z "$RUN_DIR" ]]; then
|
|
RUN_DIR="$(find .agents/nightly -mindepth 2 -maxdepth 2 -type d 2>/dev/null | sort | tail -1)"
|
|
[[ -n "$RUN_DIR" ]] || die "no nightly run directories found under .agents/nightly/"
|
|
fi
|
|
[[ -d "$RUN_DIR" ]] || die "run directory does not exist: $RUN_DIR"
|
|
|
|
DIGEST_JSON="$RUN_DIR/digest.json"
|
|
[[ -f "$DIGEST_JSON" ]] || die "digest.json not found in $RUN_DIR"
|
|
|
|
if [[ -z "$SINCE" ]]; then
|
|
SINCE="$(date -u -d '24 hours ago' +%Y-%m-%dT%H:%M:%SZ 2>/dev/null || date -u -v-24H +%Y-%m-%dT%H:%M:%SZ 2>/dev/null || echo '')"
|
|
fi
|
|
|
|
if [[ -z "$BRANCH" ]]; then
|
|
BRANCH="$(jq -r '.planned_branch // ""' "$DIGEST_JSON")"
|
|
fi
|
|
|
|
# ──── Section builders ────
|
|
|
|
build_header() {
|
|
local run_id mode run_date generated_at
|
|
run_id="$(jq -r '.run_id // "unknown"' "$DIGEST_JSON")"
|
|
mode="$(jq -r '.mode // "unknown"' "$DIGEST_JSON")"
|
|
run_date="$(jq -r '.run_date // "unknown"' "$DIGEST_JSON")"
|
|
generated_at="$(jq -r '.generated_at // "unknown"' "$DIGEST_JSON")"
|
|
|
|
printf '## Nightly Evolution — %s\n\n' "$run_date"
|
|
printf '| Field | Value |\n|---|---|\n'
|
|
printf '| Run ID | `%s` |\n' "$run_id"
|
|
printf '| Mode | %s |\n' "$mode"
|
|
printf '| Branch | `%s` |\n' "$BRANCH"
|
|
printf '| Generated | %s |\n\n' "$generated_at"
|
|
}
|
|
|
|
build_goals_section() {
|
|
local history_file=".agents/evolve/cycle-history.jsonl"
|
|
local baseline_dir=".agents/evolve/fitness-baselines"
|
|
|
|
printf '### Goals (Baseline → Final)\n\n'
|
|
|
|
local baseline_goals=""
|
|
if [[ -n "$BASELINE_LABEL" && -d "$baseline_dir/$BASELINE_LABEL" ]]; then
|
|
local baseline_file
|
|
baseline_file="$(find "$baseline_dir/$BASELINE_LABEL" -name '*.json' | sort | tail -1)"
|
|
if [[ -n "$baseline_file" ]]; then
|
|
baseline_goals="$(jq -r '.goals | length' "$baseline_file" 2>/dev/null || echo '?')"
|
|
local baseline_passing
|
|
baseline_passing="$(jq -r '[.goals[] | select(.status == "passing")] | length' "$baseline_file" 2>/dev/null || echo '?')"
|
|
printf -- '- **Baseline** (`%s`): %s/%s passing\n' "$BASELINE_LABEL" "$baseline_passing" "$baseline_goals"
|
|
fi
|
|
elif [[ -d "$baseline_dir" ]]; then
|
|
local latest_label
|
|
latest_label="$(find "$baseline_dir" -maxdepth 1 -mindepth 1 -type d -printf '%f\n' 2>/dev/null | sort | tail -1)"
|
|
if [[ -n "$latest_label" ]]; then
|
|
local latest_file
|
|
latest_file="$(find "$baseline_dir/$latest_label" -name '*.json' 2>/dev/null | sort | tail -1)"
|
|
if [[ -n "$latest_file" ]]; then
|
|
baseline_goals="$(jq -r '.goals | length' "$latest_file" 2>/dev/null || echo '?')"
|
|
local baseline_passing
|
|
baseline_passing="$(jq -r '[.goals[] | select(.status == "passing")] | length' "$latest_file" 2>/dev/null || echo '?')"
|
|
printf -- '- **Baseline** (`%s`): %s/%s passing\n' "$latest_label" "$baseline_passing" "$baseline_goals"
|
|
fi
|
|
fi
|
|
fi
|
|
|
|
if [[ -f "$history_file" ]]; then
|
|
local last_entry
|
|
last_entry="$(tail -1 "$history_file" || true)"
|
|
if [[ -n "$last_entry" ]]; then
|
|
local goals_passing goals_total
|
|
goals_passing="$(echo "$last_entry" | jq -r '.goals_passing // "?"')"
|
|
goals_total="$(echo "$last_entry" | jq -r '.goals_total // "?"')"
|
|
printf -- '- **Final**: %s/%s passing\n' "$goals_passing" "$goals_total"
|
|
fi
|
|
fi
|
|
|
|
if [[ -z "$baseline_goals" ]]; then
|
|
printf -- '- _(no baseline snapshot found)_\n'
|
|
fi
|
|
printf '\n'
|
|
}
|
|
|
|
build_cycle_history() {
|
|
local history_file=".agents/evolve/cycle-history.jsonl"
|
|
printf '### Cycle History\n\n'
|
|
|
|
if [[ ! -f "$history_file" ]]; then
|
|
printf '_(no cycle-history.jsonl found)_\n\n'
|
|
return
|
|
fi
|
|
|
|
local total improved regressed unchanged quarantined
|
|
total="$(wc -l < "$history_file" | tr -d ' ')"
|
|
improved="$(command grep -c '"result":"improved"' "$history_file" || true)"
|
|
improved="${improved%%[^0-9]*}"
|
|
regressed="$(command grep -c '"result":"regressed"' "$history_file" || true)"
|
|
regressed="${regressed%%[^0-9]*}"
|
|
unchanged="$(command grep -c '"result":"unchanged"' "$history_file" || true)"
|
|
unchanged="${unchanged%%[^0-9]*}"
|
|
quarantined="$(command grep -c '"result":"quarantined"' "$history_file" || true)"
|
|
quarantined="${quarantined%%[^0-9]*}"
|
|
: "${improved:=0}" "${regressed:=0}" "${unchanged:=0}" "${quarantined:=0}"
|
|
|
|
printf '| Metric | Count |\n|---|---|\n'
|
|
printf '| Total cycles | %s |\n' "$total"
|
|
printf '| Improved | %s |\n' "$improved"
|
|
printf '| Regressed | %s |\n' "$regressed"
|
|
printf '| Unchanged | %s |\n' "$unchanged"
|
|
printf '| Quarantined | %s |\n\n' "$quarantined"
|
|
|
|
printf '<details>\n<summary>Last 10 cycles</summary>\n\n'
|
|
printf '| # | Target | Result | Files | Duration |\n|---|---|---|---|---|\n'
|
|
tail -10 "$history_file" | while IFS= read -r line; do
|
|
[[ -z "$line" ]] && continue
|
|
local cycle work_id result files_count duration
|
|
cycle="$(echo "$line" | jq -r '.cycle // "?"')"
|
|
work_id="$(echo "$line" | jq -r '.work_id // .work_title // "?"')"
|
|
result="$(echo "$line" | jq -r '.result // "?"')"
|
|
files_count="$(echo "$line" | jq -r '(.files_changed // []) | length')"
|
|
duration="$(echo "$line" | jq -r '.duration_min // "?"')"
|
|
printf '| %s | `%s` | %s | %s | %sm |\n' "$cycle" "$work_id" "$result" "$files_count" "$duration"
|
|
done
|
|
printf '\n</details>\n\n'
|
|
}
|
|
|
|
build_runtime_flips() {
|
|
printf '### Runtime-Artifact Flips\n\n'
|
|
|
|
local readiness_status
|
|
readiness_status="$(jq -r '.readiness.ai_sane_status // "unknown"' "$DIGEST_JSON")"
|
|
local dream_status evolve_status
|
|
dream_status="$(jq -r '.phases.dream // "not-requested"' "$DIGEST_JSON")"
|
|
evolve_status="$(jq -r '.phases.evolve // "not-requested"' "$DIGEST_JSON")"
|
|
|
|
printf '| Phase | Status |\n|---|---|\n'
|
|
printf '| AI readiness | %s |\n' "$readiness_status"
|
|
printf '| Dream | %s |\n' "$dream_status"
|
|
printf '| Evolve | %s |\n\n' "$evolve_status"
|
|
|
|
local runtime_inventory
|
|
runtime_inventory="$(jq -r '.runtime.inventory_tsv // ""' "$DIGEST_JSON")"
|
|
if [[ -n "$runtime_inventory" ]]; then
|
|
local missing
|
|
missing="$(echo "$runtime_inventory" | command grep -c 'false' || true)"
|
|
missing="${missing%%[^0-9]*}"
|
|
: "${missing:=0}"
|
|
if [[ "$missing" -gt 0 ]]; then
|
|
printf '**Missing runtimes:** '
|
|
echo "$runtime_inventory" | command grep 'false' | cut -f1 | tr '\n' ',' | sed 's/,$/\n/'
|
|
printf '\n'
|
|
fi
|
|
fi
|
|
}
|
|
|
|
build_open_pr_overlap() {
|
|
printf '### Open PR Overlap\n\n'
|
|
|
|
local pr_count
|
|
pr_count="$(jq -r '.github.open_prs | length' "$DIGEST_JSON" 2>/dev/null || echo 0)"
|
|
if [[ "$pr_count" == "0" ]]; then
|
|
printf '_(no open PRs)_\n\n'
|
|
return
|
|
fi
|
|
|
|
printf '| # | Title | Branch | Changed Files |\n|---|---|---|---|\n'
|
|
jq -r '.github.open_prs[] | "| #\(.number) | \(.title) | `\(.headRefName)` | \(.changedFiles) |"' "$DIGEST_JSON" 2>/dev/null | head -15
|
|
printf '\n'
|
|
|
|
if [[ "$pr_count" -gt 15 ]]; then
|
|
printf '_... and %d more_\n\n' "$((pr_count - 15))"
|
|
fi
|
|
}
|
|
|
|
build_tracker_degradation() {
|
|
printf '### Tracker Degradation\n\n'
|
|
|
|
if ! command -v bd >/dev/null 2>&1; then
|
|
printf '_(bd not available)_\n\n'
|
|
return
|
|
fi
|
|
|
|
local open_count in_progress_count
|
|
open_count="$(bd list --status=open 2>/dev/null | command grep -c '○' || true)"
|
|
open_count="${open_count%%[^0-9]*}"
|
|
in_progress_count="$(bd list --status=in_progress 2>/dev/null | command grep -c '◐\|●' || true)"
|
|
in_progress_count="${in_progress_count%%[^0-9]*}"
|
|
: "${open_count:=0}" "${in_progress_count:=0}"
|
|
|
|
printf '| Metric | Count |\n|---|---|\n'
|
|
printf '| Open issues | %s |\n' "$open_count"
|
|
printf '| In-progress | %s |\n\n' "$in_progress_count"
|
|
|
|
local stale_items
|
|
stale_items="$(bd list --status=in_progress 2>/dev/null | command grep -E '2026-0[0-3]|2025-' | head -5 || true)"
|
|
if [[ -n "$stale_items" ]]; then
|
|
printf '**Stale in-progress (>30d):**\n```\n%s\n```\n\n' "$stale_items"
|
|
fi
|
|
}
|
|
|
|
build_transient_flakes() {
|
|
printf '### Transient Flakes\n\n'
|
|
|
|
local flake_log=".agents/evolve/flakes.jsonl"
|
|
if [[ -f "$flake_log" ]]; then
|
|
local flake_count
|
|
flake_count="$(wc -l < "$flake_log" | tr -d ' ')"
|
|
printf -- '- Recorded flakes: %s\n' "$flake_count"
|
|
printf '<details>\n<summary>Recent flakes</summary>\n\n'
|
|
tail -5 "$flake_log" | while IFS= read -r fline; do
|
|
jq -r '"- \(.timestamp // "?"): \(.test // .message // "unknown")"' <<<"$fline" 2>/dev/null || true
|
|
done
|
|
printf '\n</details>\n\n'
|
|
else
|
|
local session_state=".agents/evolve/session-state.json"
|
|
if [[ -f "$session_state" ]]; then
|
|
local last_result
|
|
last_result="$(jq -r '.last_cycle_result // "unknown"' "$session_state")"
|
|
if [[ "$last_result" == "quarantined" ]]; then
|
|
printf -- '- Last cycle was quarantined (possible flake)\n\n'
|
|
else
|
|
printf '_(no flake log; last cycle result: %s)_\n\n' "$last_result"
|
|
fi
|
|
else
|
|
printf '_(no flake tracking data found)_\n\n'
|
|
fi
|
|
fi
|
|
}
|
|
|
|
build_auto_reverts() {
|
|
printf '### Auto-Reverts\n\n'
|
|
|
|
if [[ -z "$SINCE" ]]; then
|
|
printf '_(--since not resolved; skipping)_\n\n'
|
|
return
|
|
fi
|
|
|
|
local revert_count reverts
|
|
reverts="$(git log --oneline --since="$SINCE" --grep='[Rr]evert' 2>/dev/null || true)"
|
|
if [[ -z "$reverts" ]]; then
|
|
printf '_(none in last 24h)_\n\n'
|
|
else
|
|
revert_count="$(echo "$reverts" | wc -l | tr -d ' ')"
|
|
printf '**%s revert(s) in window:**\n```\n%s\n```\n\n' "$revert_count" "$reverts"
|
|
fi
|
|
}
|
|
|
|
build_admission_context() {
|
|
printf '### Admission Context\n\n'
|
|
|
|
local gh_evidence
|
|
gh_evidence="$(jq -r '.admission_context.gh_evidence // "not present"' "$DIGEST_JSON")"
|
|
if [[ "$gh_evidence" == "not present" ]]; then
|
|
printf '_(no admission context in digest)_\n\n'
|
|
return
|
|
fi
|
|
|
|
local ci_status blocker_count
|
|
ci_status="$(jq -r '.admission_context.main_ci_baseline.status // "unknown"' "$DIGEST_JSON")"
|
|
blocker_count="$(jq -r '.admission_context.blocker_matrix.prs | length' "$DIGEST_JSON" 2>/dev/null || echo 0)"
|
|
|
|
printf '| Field | Value |\n|---|---|\n'
|
|
printf '| GitHub evidence | %s |\n' "$gh_evidence"
|
|
printf '| Main CI baseline | %s |\n' "$ci_status"
|
|
printf '| Open PR blockers | %s |\n' "$blocker_count"
|
|
|
|
if [[ "$blocker_count" -gt 0 ]] 2>/dev/null; then
|
|
printf '\n**Blocker PRs:**\n\n'
|
|
printf '| # | Branch | Files |\n|---|---|---|\n'
|
|
jq -r '.admission_context.blocker_matrix.prs[] | "| #\(.pr_number) | `\(.head_ref)` | \(.changed_file_count) |"' "$DIGEST_JSON" 2>/dev/null | head -10
|
|
printf '\n'
|
|
fi
|
|
|
|
local mode evolve_status
|
|
mode="$(jq -r '.mode // "unknown"' "$DIGEST_JSON")"
|
|
evolve_status="$(jq -r '.phases.evolve // "not-requested"' "$DIGEST_JSON")"
|
|
|
|
if [[ "$mode" != "execute" ]]; then
|
|
printf '\n**Verdict:** dry-run (no source mutation attempted)\n\n'
|
|
elif [[ "$evolve_status" == "not-requested" ]]; then
|
|
printf '\n**Verdict:** evolve not requested\n\n'
|
|
elif [[ "$evolve_status" == "ok" ]]; then
|
|
printf '\n**Verdict:** admitted and completed\n\n'
|
|
else
|
|
printf '\n**Verdict:** %s\n\n' "$evolve_status"
|
|
fi
|
|
}
|
|
|
|
build_tag_push_status() {
|
|
printf '### Tag-Push Status\n\n'
|
|
|
|
local latest_tag
|
|
latest_tag="$(git describe --tags --abbrev=0 2>/dev/null || echo '')"
|
|
if [[ -z "$latest_tag" ]]; then
|
|
printf '_(no tags found)_\n\n'
|
|
return
|
|
fi
|
|
|
|
local tag_date tag_behind
|
|
tag_date="$(git log -1 --format=%ci "$latest_tag" 2>/dev/null || echo '?')"
|
|
tag_behind="$(git rev-list "$latest_tag"..HEAD --count 2>/dev/null || echo '?')"
|
|
|
|
printf '| Field | Value |\n|---|---|\n'
|
|
printf '| Latest tag | `%s` |\n' "$latest_tag"
|
|
printf '| Tag date | %s |\n' "$tag_date"
|
|
printf '| Commits since tag | %s |\n\n' "$tag_behind"
|
|
}
|
|
|
|
# ──── Assemble ────
|
|
|
|
emit_markdown() {
|
|
build_header
|
|
build_admission_context
|
|
build_goals_section
|
|
build_cycle_history
|
|
build_runtime_flips
|
|
build_open_pr_overlap
|
|
build_tracker_degradation
|
|
build_transient_flakes
|
|
build_auto_reverts
|
|
build_tag_push_status
|
|
|
|
printf '%s\n*Generated by `nightly-pr-digest.sh` at %s*\n' '---' "$(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
|
}
|
|
|
|
emit_json() {
|
|
local tmp_md
|
|
tmp_md="$(mktemp "${TMPDIR:-/tmp}/pr-digest-XXXXXX.md")"
|
|
emit_markdown > "$tmp_md"
|
|
|
|
local admission_json="{}"
|
|
if [[ -f "$DIGEST_JSON" ]]; then
|
|
admission_json="$(jq '.admission_context // {}' "$DIGEST_JSON" 2>/dev/null || echo '{}')"
|
|
fi
|
|
|
|
jq -n \
|
|
--arg schema_version "1" \
|
|
--arg generated_at "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
|
|
--arg branch "$BRANCH" \
|
|
--arg run_dir "$RUN_DIR" \
|
|
--argjson admission "$admission_json" \
|
|
--rawfile body "$tmp_md" \
|
|
'{
|
|
schema_version: ($schema_version | tonumber),
|
|
generated_at: $generated_at,
|
|
branch: $branch,
|
|
run_dir: $run_dir,
|
|
admission_context: $admission,
|
|
pr_body: $body
|
|
}'
|
|
rm -f "$tmp_md"
|
|
}
|
|
|
|
# ──── Main ────
|
|
|
|
log "run_dir=$RUN_DIR branch=$BRANCH format=$FORMAT"
|
|
|
|
case "$FORMAT" in
|
|
markdown)
|
|
if [[ -n "$OUTPUT" ]]; then
|
|
emit_markdown > "$OUTPUT"
|
|
log "wrote $OUTPUT"
|
|
else
|
|
emit_markdown
|
|
fi
|
|
;;
|
|
json)
|
|
if [[ -n "$OUTPUT" ]]; then
|
|
emit_json > "$OUTPUT"
|
|
log "wrote $OUTPUT"
|
|
else
|
|
emit_json
|
|
fi
|
|
;;
|
|
*) die "unknown format: $FORMAT (use markdown or json)" ;;
|
|
esac
|