Summary
SMSStore.clear() only deletes SQLite rows when the database connection is currently open. If a SQLite-backed store is closed and clear() is called before the next initialize(), the in-memory list is emptied but the persisted rows remain on disk and reappear after reopening.
That makes cleanup/reset flows look successful in process (count() == 0) while durable SMS history is not actually cleared.
Evidence
Affected code:
callstack/sms/store.py:159-164 supports closing and reopening a SQLite-backed store.
callstack/sms/store.py:259-266 clears memory/pending saves, but runs DELETE FROM messages only when self._db is not None.
- Existing tests cover
clear() before first initialize with no existing persisted rows, but not clear-after-close with existing persisted rows.
No-hardware probe on main (92e0f02042bb7496d7bca2fdd7f29a0625592672):
PYTHONPATH=. uv run --no-project --with aiosqlite --with pyserial-asyncio python - <<'PY'
import asyncio, tempfile, os
from callstack.sms.store import SMSStore
from callstack.sms.types import SMS
async def main():
db = os.path.join(tempfile.gettempdir(), 'callstack-clear-after-close.db')
try: os.remove(db)
except FileNotFoundError: pass
store = SMSStore(db_path=db)
await store.initialize()
await store.save(SMS(body='persisted'))
print('count_after_save:', await store.count())
await store.close()
await store.clear()
print('count_after_clear_closed_memory:', await store.count())
await store.initialize()
print('count_after_reinitialize:', await store.count())
print('bodies_after_reinitialize:', [m.body for m in await store.list()])
await store.close()
os.remove(db)
asyncio.run(main())
PY
Actual output:
count_after_save: 1
count_after_clear_closed_memory: 0
count_after_reinitialize: 1
bodies_after_reinitialize: ['persisted']
Expected behavior
For a SQLite-backed store, await store.clear() should mean durable clear, not only in-memory clear. After clear() returns, reopening the same store should not reload rows that were supposedly cleared.
Suggested fix direction
Make clear() durable when db_path is configured even if the connection is currently closed. Possible approaches:
- Open/init the DB inside
clear() long enough to execute DELETE FROM messages, preserving the caller's previous open/closed state; or
- Record a pending clear tombstone that
initialize() applies before loading rows.
The first option is simpler but should avoid surprising callers by leaving a previously closed store open.
Acceptance criteria
- Regression test: save a row to SQLite,
close(), clear(), initialize(), then count() == 0.
clear() before first initialize() still behaves correctly.
clear() while open still deletes persisted rows.
- Pending saves made while closed are not resurrected after a clear.
Verification gates
git diff --check
PYTHONPATH=. uv run --no-project --with pytest --with pytest-asyncio --with pytest-aiohttp --with pyserial-asyncio --with aiosqlite pytest tests/test_sms_store.py -q
PYTHONPATH=. uv run --no-project --with pytest --with pytest-asyncio --with pytest-aiohttp --with pyserial-asyncio --with aiosqlite pytest tests/ -q
Duplicate check
Checked open/closed issues for SMSStore clear close initialize SQLite rows, durable store clear reopen pending SQLite, and clear SMSStore SQLite; no matching issue or PR found.
Summary
SMSStore.clear()only deletes SQLite rows when the database connection is currently open. If a SQLite-backed store is closed andclear()is called before the nextinitialize(), the in-memory list is emptied but the persisted rows remain on disk and reappear after reopening.That makes cleanup/reset flows look successful in process (
count() == 0) while durable SMS history is not actually cleared.Evidence
Affected code:
callstack/sms/store.py:159-164supports closing and reopening a SQLite-backed store.callstack/sms/store.py:259-266clears memory/pending saves, but runsDELETE FROM messagesonly whenself._db is not None.clear()before first initialize with no existing persisted rows, but not clear-after-close with existing persisted rows.No-hardware probe on
main(92e0f02042bb7496d7bca2fdd7f29a0625592672):Actual output:
Expected behavior
For a SQLite-backed store,
await store.clear()should mean durable clear, not only in-memory clear. Afterclear()returns, reopening the same store should not reload rows that were supposedly cleared.Suggested fix direction
Make
clear()durable whendb_pathis configured even if the connection is currently closed. Possible approaches:clear()long enough to executeDELETE FROM messages, preserving the caller's previous open/closed state; orinitialize()applies before loading rows.The first option is simpler but should avoid surprising callers by leaving a previously closed store open.
Acceptance criteria
close(),clear(),initialize(), thencount() == 0.clear()before firstinitialize()still behaves correctly.clear()while open still deletes persisted rows.Verification gates
Duplicate check
Checked open/closed issues for
SMSStore clear close initialize SQLite rows,durable store clear reopen pending SQLite, andclear SMSStore SQLite; no matching issue or PR found.