## 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
The JSONL branch of bootstrap-maturity.sh had two bugs:
1. Detection wrong: `jq -e '.maturity' <file>` only inspects the first
object in a JSONL stream, so files where a later line is missing the
field silently skipped.
2. Output wrong: default `jq` pretty-prints its output, producing
multi-line objects that break JSONL consumers. The unconditional
`. + {"maturity": "provisional"}` also overwrote existing maturity
values (e.g. "stable" → "provisional").
Fix:
- Count missing lines with `jq -c 'select(has("maturity") | not)'`
(per-line stream semantics).
- Transform with `jq -c 'if has("maturity") then . else . +
{"maturity": "provisional"} end'` so existing values are preserved
and output stays valid compact JSONL.
- Add bats coverage for preservation, compact output, and idempotency.
Wave 1 of flywheel signal repair epic (na-pkg):
- na-pkg.1: Fix confidence decay to process .md learnings (was skipping all non-.jsonl)
Add applyConfidenceDecayMarkdown() that reads/writes YAML frontmatter
- na-pkg.2: Reorder close-loop so citation feedback runs before maturity transitions
Ensures cited learnings get reward_count bump before promotion evaluation
- na-pkg.3: Fix GlobLearningFiles to return errors instead of silently swallowing them
- na-pkg.5: Add bootstrap-maturity.sh migration script for existing learnings
All 19 packages pass. 9 new test functions covering decay, ordering, and glob.