go-store/TODO.md
Claude b866dacdd2
feat(store): add TTL support and harden test coverage to 90.9%
Phase 0 -- Hardening:
- Fix SQLITE_BUSY under concurrent writes by setting SetMaxOpenConns(1)
  and PRAGMA busy_timeout=5000
- Add comprehensive tests: concurrent read/write (10 goroutines),
  edge cases (unicode, null bytes, SQL injection, long keys), error
  paths (closed store, invalid paths, corrupt files), group isolation,
  upsert verification, WAL mode verification, ErrNotFound wrapping
- Add benchmarks: Set, Get, GetAll (10K keys), file-backed Set

Phase 1 -- TTL Support:
- Add expires_at nullable column with schema migration for pre-TTL DBs
- SetWithTTL(group, key, value, duration) stores keys that auto-expire
- Lazy deletion on Get for expired keys
- Background purge goroutine (configurable interval, default 60s)
- Public PurgeExpired() method for manual cleanup
- Count, GetAll, Render all exclude expired entries
- Set clears TTL when overwriting a TTL key

Coverage: 73.1% -> 90.9% (48 tests, 0 races)

Co-Authored-By: Charon <developers@lethean.io>
2026-02-20 01:14:08 +00:00

2.2 KiB

TODO.md -- go-store

Dispatched from core/go orchestration. Pick up tasks in order.


Phase 0: Hardening & Test Coverage

  • Expand test coverage -- concurrent Set/Get with 10 goroutines (race test), Render() with invalid template syntax, Render() with missing template vars, Get() on non-existent group vs non-existent key, DeleteGroup() then verify GetAll() returns empty, Count() after bulk inserts, :memory: vs file-backed store, WAL mode verification. Coverage: 73.1% -> 90.9%.
  • Edge cases -- empty key, empty value, empty group, very long key (10K chars), binary-ish value (null bytes), Unicode keys and values, CJK, Arabic, SQL injection attempts, special characters.
  • Benchmark -- BenchmarkSet, BenchmarkGet, BenchmarkGetAll with 10K keys, BenchmarkSet_FileBacked.
  • go vet ./... clean -- no warnings.
  • Concurrency fix -- Added db.SetMaxOpenConns(1) and PRAGMA busy_timeout=5000 to prevent SQLITE_BUSY errors under concurrent writes.

Phase 1: TTL Support

  • Add optional expiry timestamp for keys (expires_at INTEGER column)
  • Background goroutine to purge expired entries (configurable interval, default 60s)
  • SetWithTTL(group, key, value, duration) API
  • Lazy expiry check on Get as fallback
  • PurgeExpired() public method for manual purge
  • Count, GetAll, Render exclude expired entries
  • Schema migration for pre-TTL databases (ALTER TABLE ADD COLUMN)
  • Tests for all TTL functionality including concurrent TTL access

Phase 2: Namespace Isolation

  • Group-based access control for multi-tenant use
  • Namespace prefixing to prevent key collisions across tenants
  • Per-namespace quota limits (max keys, max total size)

Phase 3: Event Hooks

  • Notify on Set / Delete for reactive patterns
  • Channel-based subscription: Watch(group, key) <-chan Event
  • Support wildcard watches (Watch(group, "*"))
  • Integration hook for go-ws to broadcast store changes via WebSocket

Workflow

  1. Virgil in core/go writes tasks here after research
  2. This repo's dedicated session picks up tasks in phase order
  3. Mark [x] when done, note commit hash