feat(devpulse): compass v2 P2 — drone @devpulse compass command (DPLAN-0212)

Thin command layer over the P1 storage core: add/query/stats/rate/archive/review
via drone @devpulse compass. Ratings shown in query output ([GOOD]/[BAD]/...),
--db flag for testing, auto-discovered (no devpulse.py change). 18 cmd tests,
seedgo 29/29, no regressions.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
AIOSAI
2026-06-16 03:01:29 -07:00
co-authored by Claude Opus 4.8
parent 0df8fee947
commit 0d042dcb2f
2 changed files with 699 additions and 0 deletions
@@ -0,0 +1,277 @@
# =================== AIPass ====================
# Name: test_compass_command.py
# Description: Tests for the compass module command router (FPLAN P2)
# Version: 1.0.0
# Created: 2026-06-16
# Modified: 2026-06-16
# =============================================
"""Tests for the compass command router (FPLAN-0212 P2).
These exercise the thin command layer (``apps/modules/compass.py``) end to
end against a real temp SQLite store via the ``--db`` flag — the same path the
live ``drone @devpulse compass`` invocation takes. Everything goes through the
module entry point (``handle_command``): the round-trip (add -> query -> see
rating) is driven and asserted entirely via the command's own console output,
so the storage handler is never reached into directly.
"""
import re
from pathlib import Path
import pytest
from aipass.devpulse.apps.modules import compass as compass_cmd
@pytest.fixture
def db(tmp_path: Path) -> str:
"""A temp DB path string, passed through to the command via --db."""
return str(tmp_path / "compass_cmd_test.db")
def _output(capsys) -> str:
"""Combined stdout+stderr (err_console / error() route to stderr)."""
captured = capsys.readouterr()
return captured.out + captured.err
def _add(capsys, db, context, decision, rating, *extra) -> int:
"""Drive an add through the command entry point; return the new id.
The id is parsed from the command's own ``#<id>`` confirmation line — we
never reach into the storage handler.
"""
capsys.readouterr() # isolate this add's output
compass_cmd.handle_command("compass", ["add", context, decision, "--rating", rating, "--db", db, *extra])
out = _output(capsys)
match = re.search(r"#(\d+)", out)
assert match, f"add did not report a new id; output was: {out!r}"
return int(match.group(1))
def _query_out(capsys, db, query, *extra) -> str:
"""Run a query via the command and return its captured output (drained)."""
capsys.readouterr() # drop anything pending so we only see this query
compass_cmd.handle_command("compass", ["query", query, "--db", db, *extra])
return _output(capsys)
def _stats_out(capsys, db) -> str:
"""Run stats via the command and return its captured output (drained)."""
capsys.readouterr()
compass_cmd.handle_command("compass", ["stats", "--db", db])
return _output(capsys)
# ---------------------------------------------------------------------------
# Routing basics
# ---------------------------------------------------------------------------
def test_rejects_unrelated_command():
"""Router returns False for commands that aren't 'compass'."""
assert compass_cmd.handle_command("watchdog", []) is False
def test_no_args_shows_introspection(capsys):
"""Bare 'compass' shows introspection that mentions compass + subcommands."""
assert compass_cmd.handle_command("compass", []) is True
out = _output(capsys).lower()
assert "compass" in out
assert "add" in out and "query" in out
def test_help_flag_shows_usage(capsys):
"""--help prints usage covering every subcommand."""
assert compass_cmd.handle_command("compass", ["--help"]) is True
out = _output(capsys).lower()
assert "usage" in out
for sub in ("add", "query", "stats", "rate", "archive", "review"):
assert sub in out
def test_unknown_subcommand_errors(capsys):
"""Unknown subcommand surfaces a clean error, still returns True."""
assert compass_cmd.handle_command("compass", ["bogus"]) is True
out = _output(capsys).lower()
assert "bogus" in out or "unknown" in out
# ---------------------------------------------------------------------------
# add -> query round-trip (rating must be visible)
# ---------------------------------------------------------------------------
def test_add_then_query_shows_rating(capsys, db):
"""add stores a decision; query surfaces it with the [GOOD] rating tag."""
assert (
compass_cmd.handle_command(
"compass",
["add", "auth fork", "chose JWT over sessions", "--rating", "good", "--note", "worked", "--db", db],
)
is True
)
add_out = _output(capsys)
assert "GOOD" in add_out # rating shown on add too
assert compass_cmd.handle_command("compass", ["query", "JWT", "--db", db]) is True
q_out = _output(capsys)
assert "GOOD" in q_out # the rating tag is the whole point
assert "chose JWT over sessions" in q_out
assert "auth fork" in q_out
def test_query_rating_filter(capsys, db):
"""--rating filters query results to the matching rating only."""
compass_cmd.handle_command("compass", ["add", "ctx good", "good choice here", "--rating", "good", "--db", db])
compass_cmd.handle_command("compass", ["add", "ctx bad", "bad choice here", "--rating", "bad", "--db", db])
capsys.readouterr() # drain add output
assert compass_cmd.handle_command("compass", ["query", "choice", "--rating", "bad", "--db", db]) is True
out = _output(capsys)
assert "bad choice here" in out
assert "good choice here" not in out
def test_add_persists_to_store(capsys, db):
"""add persists to the store; a later query surfaces it with its rating."""
_add(capsys, db, "persist ctx", "persist decision", "interesting")
out = _query_out(capsys, db, "persist")
assert "INTERESTING" in out
assert "persist decision" in out
assert "1 result(s)" in out
# ---------------------------------------------------------------------------
# stats
# ---------------------------------------------------------------------------
def test_stats_reports_counts(capsys, db):
"""stats shows total plus by-rating / by-status breakdown."""
compass_cmd.handle_command("compass", ["add", "c1", "d1", "--rating", "good", "--db", db])
compass_cmd.handle_command("compass", ["add", "c2", "d2", "--rating", "bad", "--db", db])
capsys.readouterr()
assert compass_cmd.handle_command("compass", ["stats", "--db", db]) is True
out = _output(capsys).lower()
assert "total" in out
assert "2" in out
assert "good" in out and "bad" in out
assert "active" in out
# ---------------------------------------------------------------------------
# rate
# ---------------------------------------------------------------------------
def test_rate_changes_rating(capsys, db):
"""rate <id> <rating> re-rates an existing decision."""
new_id = _add(capsys, db, "rate ctx", "rate decision", "good")
assert compass_cmd.handle_command("compass", ["rate", str(new_id), "bad", "--db", db]) is True
out = _output(capsys)
assert "BAD" in out
# Confirm the new rating sticks: querying the row now shows [BAD], not [GOOD].
q_out = _query_out(capsys, db, "rate")
assert "BAD" in q_out
assert "GOOD" not in q_out
def test_rate_missing_id_warns(capsys, db):
"""rate on a non-existent id reports 'nothing changed', does not crash."""
assert compass_cmd.handle_command("compass", ["rate", "999", "good", "--db", db]) is True
out = _output(capsys).lower()
assert "999" in out and ("nothing changed" in out or "no decision" in out)
# ---------------------------------------------------------------------------
# archive
# ---------------------------------------------------------------------------
def test_archive_removes_from_query(capsys, db):
"""archive flips status; archived rows drop out of query, stats reflect it."""
new_id = _add(capsys, db, "arch ctx", "arch decision", "good")
assert compass_cmd.handle_command("compass", ["archive", str(new_id), "--db", db]) is True
out = _output(capsys).lower()
assert "archived" in out
# Archived rows no longer surface in query...
q_out = _query_out(capsys, db, "arch")
assert "0 result(s)" in q_out
assert "arch decision" not in q_out
# ...but stats still count them under archived.
s_out = _stats_out(capsys, db).lower()
assert "archived" in s_out
# ---------------------------------------------------------------------------
# review
# ---------------------------------------------------------------------------
def test_review_surfaces_a_decision(capsys, db):
"""review surfaces an active decision with its rating shown."""
_add(capsys, db, "review ctx", "review decision", "impressive")
capsys.readouterr()
assert compass_cmd.handle_command("compass", ["review", "--db", db]) is True
out = _output(capsys)
assert "IMPRESSIVE" in out
assert "review decision" in out
def test_review_empty_store(capsys, db):
"""review on an empty store reports nothing to review (no crash)."""
assert compass_cmd.handle_command("compass", ["review", "--db", db]) is True
out = _output(capsys).lower()
assert "no active" in out or "nothing" in out
# ---------------------------------------------------------------------------
# Error surfacing — must fail loud, never silent
# ---------------------------------------------------------------------------
def test_bad_rating_error_surfaces(capsys, db):
"""add with an invalid rating surfaces the handler's ValueError message."""
assert compass_cmd.handle_command("compass", ["add", "ctx", "decision", "--rating", "terrible", "--db", db]) is True
out = _output(capsys).lower()
assert "rating" in out and "terrible" in out
# Nothing should have been stored — stats reports total 0.
assert "total decisions: 0" in _stats_out(capsys, db).lower()
def test_add_requires_rating(capsys, db):
"""add without --rating fails loud."""
assert compass_cmd.handle_command("compass", ["add", "ctx", "decision", "--db", db]) is True
out = _output(capsys).lower()
assert "rating" in out
def test_add_missing_positionals(capsys, db):
"""add with too few positional args shows usage, stores nothing."""
assert compass_cmd.handle_command("compass", ["add", "only-context", "--rating", "good", "--db", db]) is True
out = _output(capsys).lower()
assert "usage" in out
assert "total decisions: 0" in _stats_out(capsys, db).lower()
def test_query_bad_limit_errors(capsys, db):
"""query with a non-integer --limit fails loud."""
assert compass_cmd.handle_command("compass", ["query", "anything", "--limit", "abc", "--db", db]) is True
out = _output(capsys).lower()
assert "limit" in out
def test_flag_without_value_errors(capsys, db):
"""A flag given without a following value fails loud (no silent swallow)."""
assert compass_cmd.handle_command("compass", ["query", "x", "--rating"]) is True
out = _output(capsys).lower()
assert "rating" in out and "value" in out