Drop SQLite, add list mode + since filter, fix review bugs#30
Conversation
- Remove SQLiteStore (~560 lines), PostgresStore is the only backend - Lazy store init (no DB connection at import time) - psycopg/alembic move from optional to core dependencies - All 187 tests run against real Postgres via testcontainers - Add mode="list" for metadata-only queries (no content/changelog) - Add since param for time-filtered queries (SQL-level WHERE) - Both params on get_knowledge, get_alerts, get_deleted - Fix cleanup thread accumulation (alive-check guard) - Fix pyproject.toml version (0.1.0 → 0.6.0) - Remove hardcoded Cloudflare credential UUID from compose - Add Codecov upload to CI, badge row on README - Update all docs: CHANGELOG, README, CLAUDE.md, deployment guide, data dictionary Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
cmeans
left a comment
There was a problem hiding this comment.
QA Report — PR #30
Automated Tests
- 187/187 tests pass (5.36s, real Postgres via testcontainers)
- ruff: clean
- mypy (strict): clean
Manual QA Checklist
The mode and since params are not yet deployed to production, so manual MCP tool tests can't be completed against the live server. However, the test suite covers all 5 QA items with good assertions:
| # | QA Item | Test Coverage | Automated Result |
|---|---|---|---|
| 1 | List mode returns metadata only | test_get_knowledge_list_mode — asserts "data" not in response, checks fields present |
✅ PASS |
| 2 | Since filter returns recent only | test_get_knowledge_since — creates old+recent entries, asserts only recent returned |
✅ PASS |
| 3 | List mode + since combined | Covered by composition of 1+2 (both filter independently) | ✅ PASS (implicit) |
| 4 | Alerts list mode | test_get_alerts_list_mode — asserts "data" not in listing |
✅ PASS |
| 5 | Server starts without import-time crash | All 187 tests use lazy store via _LazyStore |
✅ PASS |
Code Review Findings
Bugs / Required Fixes:
src/mcp_awareness/__init__.py:3—__version__ = "0.1.0"should be"0.6.0"(mismatchespyproject.toml)docker-compose.yaml:6— Image pinned to0.5.0, should be0.6.0once releaseddocker-compose.yaml:16—AWARENESS_BACKENDenv var is dead code (not referenced in source after SQLite removal)
Medium / Worth Noting:
4. server.py:282-283 — source filter on get_knowledge is Python-side, not SQL-level (pre-existing, not introduced by this PR)
5. No dedicated test for get_alerts(since=...) at tool level (store-level is tested)
6. No test for mode="list" + since combined in a single call
7. Empty string since="" silently treated as None — could confuse callers
Not Issues (Verified OK):
to_list_dict()correctly excludesdataandchangelog, includeslogical_keywhen presentsincefiltering is SQL-level (updated >= %s) in all postgres store methods- Store protocol properly updated with
sinceon all relevant methods - Lazy store init pattern works correctly for async/single-threaded FastMCP
- Credential UUID properly parameterized in compose
Recommendation
Merge-ready with minor fixes — items 1-3 above should be addressed before merge. The core functionality (list mode, since filter, SQLite removal, lazy init) is solid and well-tested.
🤖 QA performed by Claude Code
Suggested fixes for QA findings1. from importlib.metadata import version
__version__ = version("mcp-awareness-server")2. 3. |
- __init__.py: use importlib.metadata instead of hardcoded version string - docker-compose.yaml: remove AWARENESS_BACKEND (dead after SQLite removal) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- docker-compose.demo.yaml: remove dead AWARENESS_BACKEND env var - CLAUDE.md: replace stale AWARENESS_DATA ref with AWARENESS_PG_DATA - simulate_edge.py: fix --data-dir arg to --dsn for PostgresStore Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
QA Complete — All 5 Manual Tests PASSAll tests executed via live MCP tool calls against an isolated test instance (port 8421, separate
Automated tests
Code review findings (all addressed)
Remaining medium items (non-blocking)
Ready for 🤖 QA performed by Claude Code |
cmeans
left a comment
There was a problem hiding this comment.
QA Complete — All 5 Manual Tests PASS
All tests executed via live MCP tool calls against an isolated test instance (port 8421, separate awareness_qa database, claude -p --strict-mcp-config).
| # | Test | Result |
|---|---|---|
| 1 | List mode returns metadata only | ✅ PASS |
| 2 | Since filter returns recent entries only | ✅ PASS |
| 3 | List mode + since combined | ✅ PASS |
| 4 | Alerts list mode | ✅ PASS |
| 5 | Server starts without import-time crash | ✅ PASS |
Automated tests
- 187/187 pass (real Postgres via testcontainers)
- ruff: clean
- mypy (strict): clean
Code review findings — all addressed
→ Fixed: derives from__init__.pyversion mismatchimportlib.metadatadocker-compose.yamlimage tag0.5.0→ Expected pre-release→ RemovedAWARENESS_BACKENDdead env var
Non-blocking items for follow-up
server.py:282—sourcefilter onget_knowledgeis Python-side (pre-existing)- No test for
get_alerts(since=...)at tool level - Empty string
since=""silently treated asNone
🤖 QA performed by Claude Code
…tests - Push get_knowledge source filter from Python-side to SQL-level WHERE clause - Reject empty-string since param on get_knowledge, get_alerts, get_deleted - Add tests: get_alerts(since=...), source SQL filter, empty since validation - Test count: 187 → 190 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
cmeans
left a comment
There was a problem hiding this comment.
QA Review — Round 2 (Full Re-review)
Automated Checks
- 190/190 tests pass (5.87s, real Postgres via testcontainers)
- ruff: clean
- mypy (strict): clean
Manual QA — All 8 Tests PASS
All tests executed via live MCP tool calls against an isolated test instance (port 8421, separate database, claude -p --strict-mcp-config).
| # | Test | Result | Notes |
|---|---|---|---|
| 1 | List mode — metadata only | ✅ PASS | No data/content/changelog in response |
| 2 | Since filter — recent only | ✅ PASS | SQL-level updated >= %s filtering works |
| 3 | List mode + since combined | ✅ PASS | Both constraints applied simultaneously |
| 4 | Alerts list mode | ✅ PASS | Alert metadata only, no data payloads |
| 5 | Server starts cleanly | ✅ PASS | All tool calls succeeded, no import-time errors |
| 6 | Source filter at SQL level | ✅ PASS | Only matching source returned, "other-source" excluded |
| 7 | Empty since rejected | ✅ PASS | Returns {"error": "since cannot be empty; ..."} |
| 8 | Alerts since filter | ✅ PASS | Only alerts after cutoff timestamp returned |
Code Review Summary
22 files reviewed across 5 commits. All prior findings (version mismatch, dead env var, source filter not at SQL level, missing since validation) have been addressed.
New finding (minor, non-blocking):
examples/test_new_tools.py:5references staleAWARENESS_DATA_DIRenv var removed in this PR. Either delete the file or update the usage instructions.
Observation (informational):
to_list_dict()returnsdescription: ""for alerts (alerts don't have a description field in their data). Not a bug — just worth noting if list mode output is ever surfaced in UI.docker-compose.yaml:6still pins0.5.0— expected pre-release; update after merge+build.
Security: All SQL parametrized, no injection vectors, input validation on since, secret path auth intact, container runs as non-root.
Breaking changes: None. All new parameters are optional with backward-compatible defaults.
Verdict
PR is ready for merge. All automated and manual QA checks pass. All prior review findings addressed.
🤖 QA performed by Claude Code
Summary
main().get_knowledge(mode="list")returns metadata only (id, type, source, description, tags, created, updated) without content or changelog. Also onget_alertsandget_deleted. Addresses agent UX feedback Storage abstraction, soft delete, secure deployment, README reframe #1.get_knowledge(since="2026-03-23T06:00:00Z")returns only entries updated after the given timestamp, at SQL level. Also onget_alerts,get_entries,get_deleted. Addresses agent UX feedback Non-blocking cleanup, tools reference, screenshot resize #2.Review findings addressed
_LazyStoreis_alive()guardQA
Prerequisites
Automated tests
Manual tests (via MCP tools)
Connect to the running server, then:
Expected: entries with id, type, source, description, tags, created, updated — no data/content/changelog
Expected: only entries updated after the given timestamp
Expected: lightweight metadata for recent entries only
Expected: alert metadata without full data payloads
Expected: only entries with source "mcp-awareness-project" returned (verified via SQL, not Python post-filter)
Expected: error response — "since cannot be empty; omit or provide an ISO 8601 timestamp"
Expected: only alerts updated after the given timestamp
Deploy to test instance and verify startup logs show migrations running (not import-time crash)
🤖 Generated with Claude Code