| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220 |
- from __future__ import annotations
- import sqlite3
- from uuid import uuid4
- from hermes_mcp.store import (
- DB_PATH,
- delete_concern,
- init_db,
- prune_older_than_hours,
- upsert_decision_profile,
- upsert_concern,
- upsert_cycle,
- upsert_decision,
- upsert_strategy_assignment,
- upsert_strategy_group,
- upsert_narrative,
- upsert_observation,
- upsert_regime_sample,
- upsert_state,
- )
- def _count(table: str, value: str, column: str = "concern_id") -> int:
- with sqlite3.connect(DB_PATH) as conn:
- conn.row_factory = sqlite3.Row
- row = conn.execute(f"select count(*) as n from {table} where {column} = ?", (value,)).fetchone()
- return int(row["n"] if row else 0)
- def _total_count(table: str) -> int:
- with sqlite3.connect(DB_PATH) as conn:
- conn.row_factory = sqlite3.Row
- row = conn.execute(f"select count(*) as n from {table}").fetchone()
- return int(row["n"] if row else 0)
- def test_delete_concern_purges_related_rows():
- init_db()
- concern_id = f"test:{uuid4().hex}"
- cycle_id = f"cycle:{uuid4().hex}"
- decision_id = f"decision:{uuid4().hex}"
- action_id = f"action:{uuid4().hex}"
- upsert_concern(
- id=concern_id,
- account_id="acct-1",
- market_symbol="xrpusd",
- base_currency="XRP",
- quote_currency="USD",
- strategy_id="trend-1",
- source="test",
- status="active",
- notes="cleanup target",
- )
- upsert_cycle(id=cycle_id, started_at="2026-04-19T00:00:00+00:00", finished_at=None, status="ok", trigger="test")
- upsert_observation(id=f"obs:{uuid4().hex}", cycle_id=cycle_id, concern_id=concern_id, source="test", kind="snapshot", payload_json="{}")
- upsert_state(
- id=f"state:{uuid4().hex}",
- cycle_id=cycle_id,
- concern_id=concern_id,
- market_regime="bull",
- volatility_state="normal",
- liquidity_state="good",
- sentiment_pressure="neutral",
- event_risk="low",
- execution_quality="good",
- confidence=0.9,
- payload_json="{}",
- )
- upsert_narrative(
- id=f"narr:{uuid4().hex}",
- cycle_id=cycle_id,
- concern_id=concern_id,
- summary="cleanup target",
- key_drivers_json="[]",
- risk_flags_json="[]",
- uncertainties_json="[]",
- confidence=0.8,
- )
- upsert_decision(
- id=decision_id,
- cycle_id=cycle_id,
- concern_id=concern_id,
- action="replace_with_grid",
- target_strategy="grid-1",
- target_policy_json="{}",
- reason_summary="cleanup target",
- confidence=0.7,
- requires_action=True,
- )
- upsert_regime_sample(id=f"regime:{uuid4().hex}", cycle_id=cycle_id, concern_id=concern_id, timeframe="1h", regime_json="{}", captured_at="2026-04-19T00:00:00+00:00")
- with sqlite3.connect(DB_PATH) as conn:
- conn.execute(
- "insert into actions(id, decision_id, target, command, request_json, response_json, status, executed_at) values(?, ?, ?, ?, ?, ?, ?, ?)",
- (action_id, decision_id, "trader", "switch", "{}", None, "pending", None),
- )
- conn.commit()
- deleted = delete_concern(concern_id=concern_id)
- assert deleted["concerns"] == 1
- assert deleted["decisions"] == 1
- assert deleted["actions"] == 1
- assert deleted["observations"] == 1
- assert deleted["states"] == 1
- assert deleted["narratives"] == 1
- assert deleted["regime_samples"] == 1
- assert _count("concerns", concern_id, "id") == 0
- for table in ("observations", "states", "narratives", "decisions", "coverage_gaps", "regime_samples"):
- assert _count(table, concern_id) == 0
- assert _count("actions", decision_id, "decision_id") == 0
- def test_prune_older_than_hours_keeps_concerns_and_config_tables():
- init_db()
- concern_id = f"test:{uuid4().hex}"
- cycle_id = f"cycle:{uuid4().hex}"
- decision_id = f"decision:{uuid4().hex}"
- profile_id = f"profile:{uuid4().hex}"
- group_id = f"group:{uuid4().hex}"
- assignment_id = f"assignment:{uuid4().hex}"
- old_at = "2026-04-24T00:00:00+00:00"
- upsert_concern(
- id=concern_id,
- account_id="acct-1",
- market_symbol="xrpusd",
- base_currency="XRP",
- quote_currency="USD",
- strategy_id="trend-1",
- source="test",
- status="active",
- notes="preserve me",
- )
- upsert_decision_profile(id=profile_id, name="Config profile", config={"keep": True})
- upsert_strategy_group(id=group_id, concern_id=concern_id, name="Config group", strategy_family="mixed", decision_profile_id=profile_id)
- upsert_strategy_assignment(id=assignment_id, strategy_group_id=group_id, strategy_id="trend-1", strategy_type="trend_follower", role="primary")
- upsert_cycle(id=cycle_id, started_at=old_at, finished_at=None, status="ok", trigger="test")
- upsert_observation(id=f"obs:{uuid4().hex}", cycle_id=cycle_id, concern_id=concern_id, source="test", kind="snapshot", payload_json="{}", observed_at=old_at)
- upsert_state(
- id=f"state:{uuid4().hex}",
- cycle_id=cycle_id,
- concern_id=concern_id,
- market_regime="bull",
- volatility_state="normal",
- liquidity_state="good",
- sentiment_pressure="neutral",
- event_risk="low",
- execution_quality="good",
- confidence=0.9,
- payload_json="{}",
- created_at=old_at,
- )
- upsert_narrative(
- id=f"narr:{uuid4().hex}",
- cycle_id=cycle_id,
- concern_id=concern_id,
- summary="old",
- key_drivers_json="[]",
- risk_flags_json="[]",
- uncertainties_json="[]",
- confidence=0.8,
- created_at=old_at,
- )
- upsert_decision(
- id=decision_id,
- cycle_id=cycle_id,
- concern_id=concern_id,
- action="replace_with_grid",
- target_strategy="grid-1",
- target_policy_json="{}",
- reason_summary="old",
- confidence=0.7,
- requires_action=True,
- created_at=old_at,
- )
- upsert_regime_sample(id=f"regime:{uuid4().hex}", cycle_id=cycle_id, concern_id=concern_id, timeframe="1h", regime_json="{}", captured_at=old_at)
- with sqlite3.connect(DB_PATH) as conn:
- conn.execute(
- "insert into actions(id, decision_id, target, command, request_json, response_json, status, executed_at) values(?, ?, ?, ?, ?, ?, ?, ?)",
- (f"action:{uuid4().hex}", decision_id, "trader", "switch", "{}", None, "done", old_at),
- )
- conn.commit()
- before_counts = {
- "cycles": _total_count("cycles"),
- "decisions": _total_count("decisions"),
- "actions": _total_count("actions"),
- "observations": _total_count("observations"),
- "states": _total_count("states"),
- "narratives": _total_count("narratives"),
- "coverage_gaps": _total_count("coverage_gaps"),
- "regime_samples": _total_count("regime_samples"),
- }
- deleted = prune_older_than_hours(24)
- assert deleted["cycles"] == before_counts["cycles"] - _total_count("cycles")
- assert deleted["decisions"] == before_counts["decisions"] - _total_count("decisions")
- assert deleted["actions"] == before_counts["actions"] - _total_count("actions")
- assert deleted["observations"] == before_counts["observations"] - _total_count("observations")
- assert deleted["states"] == before_counts["states"] - _total_count("states")
- assert deleted["narratives"] == before_counts["narratives"] - _total_count("narratives")
- assert deleted["coverage_gaps"] == before_counts["coverage_gaps"] - _total_count("coverage_gaps")
- assert deleted["regime_samples"] == before_counts["regime_samples"] - _total_count("regime_samples")
- assert "concerns" not in deleted
- assert "decision_profiles" not in deleted
- assert "strategy_groups" not in deleted
- assert "strategy_assignments" not in deleted
- assert _count("concerns", concern_id, "id") == 1
- assert _count("decision_profiles", profile_id, "id") == 1
- assert _count("strategy_groups", group_id, "id") == 1
- assert _count("strategy_assignments", assignment_id, "id") == 1
- assert _count("decisions", concern_id) == 0
- assert _count("observations", concern_id) == 0
- assert _count("states", concern_id) == 0
- assert _count("narratives", concern_id) == 0
- assert _count("regime_samples", concern_id) == 0
|