feat: add pipeline health checks module and CLI runner

- Create health/ package with HealthStatus, HealthCheck, HealthReport
- Add check_motion_freshness, check_embedding_coverage, check_llm_coverage
- Add scripts/health_check.py CLI with text/JSON output and exit codes
- Add comprehensive tests for core, checks, and CLI

P4-005: Pipeline health checks
This commit is contained in:
2026-05-01 00:02:45 +02:00
parent 04cc62ea06
commit e352d7c7bc
6 changed files with 495 additions and 0 deletions
+69
View File
@@ -0,0 +1,69 @@
import sys
from unittest.mock import MagicMock, patch
import pytest
from scripts.health_check import main
class TestHealthCheckCLI:
@patch("scripts.health_check.duckdb.connect")
@patch("scripts.health_check.config")
def test_all_ok_exits_0(self, mock_config, mock_connect):
mock_config.DATABASE_PATH = "/fake/db"
mock_conn = MagicMock()
mock_conn.execute.return_value.fetchone.side_effect = [
[150], # motion count
[100], # total motions
[100], # embeddings count
[100], # total motions
[0], # missing explanations
]
mock_connect.return_value = mock_conn
with patch.object(sys, "argv", ["health_check"]):
exit_code = main()
assert exit_code == 0
@patch("scripts.health_check.duckdb.connect")
@patch("scripts.health_check.config")
def test_critical_exits_2(self, mock_config, mock_connect):
mock_config.DATABASE_PATH = "/fake/db"
mock_conn = MagicMock()
mock_conn.execute.return_value.fetchone.side_effect = [
[0], # no recent motions
[100], # total motions
[100], # embeddings count
[100], # total motions
[0], # missing explanations
]
mock_connect.return_value = mock_conn
with patch.object(sys, "argv", ["health_check"]):
exit_code = main()
assert exit_code == 2
@patch("scripts.health_check.duckdb.connect")
@patch("scripts.health_check.config")
def test_json_format(self, mock_config, mock_connect, capsys):
mock_config.DATABASE_PATH = "/fake/db"
mock_conn = MagicMock()
mock_conn.execute.return_value.fetchone.side_effect = [
[150], [100], [100], [100], [0]
]
mock_connect.return_value = mock_conn
with patch.object(sys, "argv", ["health_check", "--format", "json"]):
main()
captured = capsys.readouterr()
assert '"status": "ok"' in captured.out
assert '"exit_code": 0' in captured.out
@patch("scripts.health_check.duckdb.connect")
def test_db_connect_failure_exits_2(self, mock_connect):
mock_connect.side_effect = Exception("cannot open")
with patch.object(sys, "argv", ["health_check"]):
exit_code = main()
assert exit_code == 2