MODE=$(helios h3-harness --db "$DB" "PRAGMA journalmode")
Root cause 1 — battery hang (300s timeout). The PRAGMA/schema check called helios h3-harness inside the script. h3-harness is a long-running server subcommand (binds a port, serves forever), so the battery never returned from the check even though every HTTP leg had already passed.
Root cause 2 — false failure in the log scan. grep -i ERROR matches the substring ERROR inside error_code, so by-design 401 lines like error_code SESSION_TOKEN_MISSING were treated as failures.
Fix 1 — never invoke a server-starting CLI subcommand inside a battery; query the SQLite file directly with sqlite3 (read-only URI, no write lock on the live server DB):
# BAD — hangs the battery until the 300s timeout:
MODE=$(helios h3-harness --db "$DB" "PRAGMA journal_mode")
# GOOD — direct, read-only, guaranteed to return:
if MODE=$(sqlite3 "file:$DB?mode=ro" "PRAGMA journal_mode;"); then
[ "$MODE" = "wal" ] && pass "journal_mode=wal" || fail "journal_mode=$MODE (want wal)"
else
fail "cannot read journal_mode from $DB (is the server DB path correct?)"
fi
Schema checks use the same pattern: sqlite3 "file:$DB?mode=ro" "SELECT count(*) FROM sqlite_master WHERE type='table' AND name='kv';" and PRAGMA integrity_check; — the server stays started once by the test runner, never by the battery.
Fix 2 — exclude expected by-design codes by name before failing the log scan:
# BAD — matches error_code SESSION_TOKEN_MISSING as an ERROR:
grep -iE 'ERROR' "$LOG" && fail "unexpected ERROR in log"
# GOOD — whitelist by code name; separators may be '=', ':', or space; case-insensitive:
EXPECTED_CODES=(SESSION_TOKEN_MISSING SESSION_EXPIRED) # expected 401 flows
EXPECTED_RE=$(IFS='|'; printf 'error_code[=: ]+(%s)\\b' "${EXPECTED_CODES[*]}")
GENUINE=$(grep -iE 'ERROR' "$LOG" | grep -viE "$EXPECTED_RE" || true)
[ -n "$GENUINE" ] && { fail "unexpected ERROR lines in log:"; printf '%s\n' "$GENUINE" >&2; } \
|| pass "log scan clean (by-design 401 codes excluded by name)"
Full fixed script: /tmp/battery-demo/e2e-battery.sh (also adds command -v sqlite3 guard, set -euo pipefail, and a final exit 1 on any failure).
Verified with real SQLite 3.46.1 and realistic log lines in `/tmp/battery-demo/`: | # | Test | Result | |---|------|--------| | 1 | Bug repro: `grep -icE ERROR` on the log counted **4** — including 2 by-design 401 lines (`SESSION_TOKEN_MISSING`, `SESSION_EXPIRED`) | Bug confirmed | | 2 | `sqlite3 "file:helios.db?mode=ro" "PRAGMA journal_mode;"` → `wal` (read-only, returns instantly, no server process) | Pass | | 3 | `sqlite3` schema query + `PRAGMA integrity_check` → `ok` | Pass | | 4 | Full battery vs regression log (2 genuine errors + 2 expected 401s) → flags only the genuine errors (`database disk image is malformed`, `error_code DATABASE_CORRUPT`), exit 1 | Pass | | 5 | Log with **only** expected 401 codes → `BATTERY PASSED`, exit 0 | Pass | | 6 | Edge: lowercase `session_token_missing` with `error_code:` separator → still excluded (`grep -i` + flexible separator), PASS | Pass | | 7 | Edge: missing DB file → single clean FAIL message, exit 1, no hang | Pass | | 8 | Edge: entire battery completes in **17 ms** vs the previous 300 s timeout — root cause (server subcommand) gone | Pass | Also caught during verification: a nested-quoting pitfall (`\b` degenerating to a literal backspace) — resolved by using `printf '...\\b'` with single quotes so `\\` → `\` at `printf` level.
{"model": "deepseek-v4-flash", "problem_class": "bash-e2e-battery-hang-on-cli-subcommand", "result": "passed", "tests": 8}