mirror of
https://github.com/boshu2/agentops.git
synced 2026-09-14 15:08:13 +08:00
10db732740
## What Under `set -euo pipefail`, a `jq ... 2>/dev/null | wc -l` substitution aborts the entire script when `jq` hits a malformed JSON line: `2>/dev/null` suppresses jq's stderr but not its non-zero exit code, `pipefail` propagates that through the pipeline, and `set -e` then kills the script mid-run (leaving partial state). ## Fix Append `|| echo 0` to the unguarded substitutions: - **`scripts/bootstrap-maturity.sh` line 65** — reads the raw `.jsonl` file directly, so a malformed line genuinely aborts the migration before the summary prints. Verified empirically and caught by the regression test (test fails against the unguarded copy with `status != 0`). - **`scripts/evolve-capture-daily-learning.sh` lines 59-62 (4x)** — matches the already-guarded `grep -c` on line 58. Verification note: in normal operation `TODAY_CYCLES` is pre-sanitized by the line-55 `jq ... || true` filter, so these lines don't see malformed input in practice. The guard is defense-in-depth that pins abort-proof behavior if malformed content ever reaches them (e.g., a future refactor drops the line-55 sanitization). `halt-check.sh` is intentionally out of scope (`set -uo`, no `-e` — degrades, doesn't abort). ## Test `tests/scripts/jq-wc-pipefail-guards.bats` (5 tests): - Malformed-input fixtures for both scripts prove neither aborts and the consolidated artifacts still get written. - A guarded/unguarded expression pair (positive + negative control) pins the `|| echo 0` mechanism so a future edit can't silently drop it. ## Local validation - `bats tests/scripts/jq-wc-pipefail-guards.bats` — 5/5 green - `shellcheck scripts/evolve-capture-daily-learning.sh scripts/bootstrap-maturity.sh` — clean - Existing `tests/scripts/bootstrap-maturity.bats` — still 4/4 green Closes-scenario: ag-1j1#jq-wc-guards Bounded-context: BC5-Runtime Evidence: bats tests/scripts/jq-wc-pipefail-guards.bats
90 lines
2.7 KiB
Bash
Executable File
90 lines
2.7 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# bootstrap-maturity.sh — One-time migration: add maturity: provisional to
|
|
# existing .md learnings that lack a maturity field.
|
|
#
|
|
# Usage: bash scripts/bootstrap-maturity.sh [learnings-dir]
|
|
# Default learnings dir: .agents/learnings
|
|
#
|
|
# Safe to run multiple times — skips files that already have maturity field.
|
|
|
|
set -euo pipefail
|
|
|
|
LEARNINGS_DIR="${1:-.agents/learnings}"
|
|
|
|
if [[ ! -d "$LEARNINGS_DIR" ]]; then
|
|
echo "Directory not found: $LEARNINGS_DIR"
|
|
exit 1
|
|
fi
|
|
|
|
total=0
|
|
updated=0
|
|
skipped=0
|
|
|
|
for file in "$LEARNINGS_DIR"/*.md; do
|
|
[[ -f "$file" ]] || continue
|
|
total=$((total + 1))
|
|
|
|
# Check if file has YAML frontmatter
|
|
head_line=$(head -1 "$file")
|
|
if [[ "$head_line" != "---" ]]; then
|
|
skipped=$((skipped + 1))
|
|
continue
|
|
fi
|
|
|
|
# Check if maturity field already exists in frontmatter
|
|
if grep -q "^maturity:" "$file"; then
|
|
skipped=$((skipped + 1))
|
|
continue
|
|
fi
|
|
|
|
# Add maturity: provisional after the opening ---
|
|
# Use a temp file to avoid in-place edit portability issues
|
|
tmpfile=$(mktemp)
|
|
{
|
|
echo "---"
|
|
echo "maturity: provisional"
|
|
tail -n +2 "$file"
|
|
} > "$tmpfile"
|
|
mv "$tmpfile" "$file"
|
|
updated=$((updated + 1))
|
|
done
|
|
|
|
# Process .jsonl files: add "maturity":"provisional" if missing
|
|
jsonl_total=0
|
|
jsonl_updated=0
|
|
jsonl_skipped=0
|
|
|
|
if command -v jq >/dev/null 2>&1; then
|
|
for file in "$LEARNINGS_DIR"/*.jsonl; do
|
|
[[ -f "$file" ]] || continue
|
|
jsonl_total=$((jsonl_total + 1))
|
|
|
|
# Count lines missing the maturity field. JSONL is one object per
|
|
# line, so we must treat each line independently — a single -e check
|
|
# only inspects the first object.
|
|
missing=$(jq -c 'select(has("maturity") | not)' "$file" 2>/dev/null | wc -l | tr -d ' ' || echo 0)
|
|
if [[ "${missing:-0}" -eq 0 ]]; then
|
|
jsonl_skipped=$((jsonl_skipped + 1))
|
|
continue
|
|
fi
|
|
|
|
# Transform each object: add maturity only when missing, preserving
|
|
# existing values. Use -c so output stays valid JSONL (compact, one
|
|
# object per line) instead of jq's default pretty-printed stream.
|
|
tmpfile=$(mktemp)
|
|
if jq -c 'if has("maturity") then . else . + {"maturity": "provisional"} end' "$file" > "$tmpfile" 2>/dev/null; then
|
|
mv "$tmpfile" "$file"
|
|
jsonl_updated=$((jsonl_updated + 1))
|
|
else
|
|
rm -f "$tmpfile"
|
|
jsonl_skipped=$((jsonl_skipped + 1))
|
|
fi
|
|
done
|
|
else
|
|
echo "Warning: jq not found — skipping .jsonl files" >&2
|
|
fi
|
|
|
|
echo "Bootstrap maturity complete:"
|
|
echo " .md files: $total total, $updated updated, $skipped skipped"
|
|
echo " .jsonl files: $jsonl_total total, $jsonl_updated updated, $jsonl_skipped skipped"
|