Skip to content

fix(reliability): route session-response write through WAL helper, not inline sqlite (A-20)#64

Merged
AVADSA25 merged 1 commit into
mainfrom
fix/pr3-a20-inline-sqlite
May 22, 2026
Merged

fix(reliability): route session-response write through WAL helper, not inline sqlite (A-20)#64
AVADSA25 merged 1 commit into
mainfrom
fix/pr3-a20-inline-sqlite

Conversation

@AVADSA25
Copy link
Copy Markdown
Owner

Summary

Closes A-20 (MEDIUM) — codec.py's voice handler opened a bare sqlite3.connect(DB_PATH) for one UPDATE sessions SET response=? WHERE id=? with no WAL/busy_timeout, risking database is locked under concurrent Phase-3 agent-runner + voice writes.

Correction over the audit's literal fix

The audit suggested CodecMemory().update_session_response(), but the sessions table is owned by codec_core (CodecMemory owns conversations). So the helper lives in codec_core, where the table + save_task already are.

What changed

codec_core.py:

  • _db_connect() — connection helper setting PRAGMA journal_mode=WAL + busy_timeout=5000 (matches CodecMemory + routes/_shared.get_db()).
  • update_session_response(rid, response) — truncates to 500 chars (prior behavior), never raises (logs DB errors; the caller already spoke the answer).
  • Root-cause fix beyond the one site: retrofitted all four real session connects (init_db, save_task, get_memory, get_recent_conversations) to use _db_connect() — they shared the same no-pragma lock risk. (The string-template connects inside the deprecated build_session_script are untouched.)

codec.py:

  • Replaced the inline sqlite UPDATE with update_session_response(rid, answer[:500]).
  • Removed the now-unused sqlite3 + DB_PATH imports (ruff 73 → 72).

The dashboard qchat_db/vibe_db lazy globals already set pragmas — left as-is per the audit.

Verification

9 tests in tests/test_session_response_update.py: WAL+busy_timeout pragmas, round-trip write, 500-char truncation, None/nonexistent-rid no-crash, non-str coercion, surfaces in get_memory, source invariants (no inline UPDATE in codec.py; exactly one bare connect in codec_core — inside _db_connect).

Full suite: 1365 passing, 23 pre-existing failures unchanged (zero new). Net-negative ruff. No skills/ touched → no manifest regen.

Reference: docs/audits/PHASE-1-CODE-QUALITY.md finding A-20.

🤖 Generated with Claude Code

…t inline sqlite (A-20)

Closes A-20 — codec.py's voice handler opened a bare sqlite3.connect(DB_PATH)
for one `UPDATE sessions SET response=? WHERE id=?` with no WAL/busy_timeout,
risking "database is locked" under concurrent Phase-3 agent-runner + voice
writes.

## Correction over the audit's literal fix

The audit suggested CodecMemory().update_session_response(), but the `sessions`
table is owned by codec_core (CodecMemory owns `conversations`). So the helper
lives in codec_core.

## What changed

codec_core.py:
- _db_connect() — connection helper setting PRAGMA journal_mode=WAL +
  busy_timeout=5000 (matches CodecMemory + routes/_shared.get_db()).
- update_session_response(rid, response) — truncates to 500 chars, never
  raises (logs DB errors; the caller already spoke the answer).
- Retrofitted ALL four real session connects (init_db, save_task, get_memory,
  get_recent_conversations) to use _db_connect() — they shared the same
  no-pragma lock risk. (String-template connects in the deprecated
  build_session_script untouched.)

codec.py:
- Replaced the inline sqlite UPDATE with update_session_response(rid, answer[:500]).
- Removed now-unused `sqlite3` + `DB_PATH` imports (ruff 73 -> 72).

Dashboard qchat_db/vibe_db lazy globals already set pragmas — left as-is per
the audit.

## Verification

9 tests in tests/test_session_response_update.py (WAL+busy_timeout pragmas,
round-trip, 500-char truncation, None/nonexistent rid no-crash, non-str
coercion, surfaces in get_memory, source invariants). Full suite 1365 passing,
23 pre-existing failures unchanged (zero new). Net-negative ruff. No skills/
touched -> no manifest regen.

Reference: docs/audits/PHASE-1-CODE-QUALITY.md finding A-20.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@AVADSA25 AVADSA25 merged commit 535f87a into main May 22, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants