You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
111 lines
3.7 KiB
111 lines
3.7 KiB
"""Parity tests: verify agent tools can achieve what humans can.
|
|
|
|
These tests ensure the agent-native architecture satisfies the parity principle:
|
|
"Whatever the user can do through the UI/scripts, the agent can achieve through tools."
|
|
"""
|
|
|
|
import os
|
|
import pytest
|
|
|
|
pytest.importorskip("duckdb")
|
|
|
|
|
|
class TestDatabaseParity:
|
|
"""Agent database queries vs human SQL queries."""
|
|
|
|
def test_agent_query_motions_matches_raw_sql(self, tmp_duckdb_path):
|
|
"""Human: SELECT * FROM motions LIMIT 10
|
|
Agent: query_motions(db_path, limit=10)
|
|
"""
|
|
import duckdb
|
|
from agent_tools.database import query_motions
|
|
|
|
# Human approach — handle empty DB gracefully
|
|
con = duckdb.connect(tmp_duckdb_path)
|
|
try:
|
|
human_result = con.execute("SELECT * FROM motions LIMIT 10").fetchdf().to_dict("records")
|
|
except Exception:
|
|
human_result = []
|
|
con.close()
|
|
|
|
# Agent approach
|
|
agent_result = query_motions(tmp_duckdb_path, limit=10)
|
|
|
|
# Both should return lists
|
|
assert isinstance(human_result, list)
|
|
assert isinstance(agent_result, list)
|
|
assert len(agent_result) == len(human_result)
|
|
|
|
def test_agent_pipeline_status_matches_raw_query(self, tmp_duckdb_path):
|
|
"""Human: SELECT COUNT(*) FROM motions
|
|
Agent: query_pipeline_status(db_path)
|
|
"""
|
|
import duckdb
|
|
from agent_tools.database import query_pipeline_status
|
|
|
|
con = duckdb.connect(tmp_duckdb_path)
|
|
try:
|
|
human_count = con.execute("SELECT COUNT(*) FROM motions").fetchone()[0]
|
|
except Exception:
|
|
human_count = 0
|
|
con.close()
|
|
|
|
agent_status = query_pipeline_status(tmp_duckdb_path)
|
|
|
|
assert agent_status["motion_count"] == human_count
|
|
assert "healthy" not in agent_status
|
|
|
|
|
|
class TestHealthCheckParity:
|
|
"""Agent health check vs human script execution.
|
|
|
|
NOTE: The composite pipeline_check_health workflow has been removed.
|
|
The agent now queries raw status and makes its own health determination.
|
|
"""
|
|
|
|
def test_agent_queries_raw_status(self, tmp_duckdb_path):
|
|
"""Human: python scripts/health_check.py
|
|
Agent: query_pipeline_status(db_path) + reasoning
|
|
"""
|
|
from agent_tools.database import query_pipeline_status
|
|
|
|
status = query_pipeline_status(tmp_duckdb_path)
|
|
|
|
assert isinstance(status, dict)
|
|
assert "motion_count" in status
|
|
assert "svd_window_count" in status
|
|
assert "healthy" not in status
|
|
|
|
|
|
class TestIntegrationAgentDiagnosticLoop:
|
|
"""Integration: Agent performs full diagnostic loop."""
|
|
|
|
def test_agent_diagnoses_stale_data(self, tmp_duckdb_path):
|
|
"""Agent loop:
|
|
1. Query pipeline status
|
|
2. Identify issue (empty DB = no data)
|
|
3. Suggest remediation
|
|
"""
|
|
from agent_tools.database import query_pipeline_status
|
|
|
|
# Step 1: Query status
|
|
status = query_pipeline_status(tmp_duckdb_path)
|
|
|
|
# Step 2: Agent reasoning (simulated)
|
|
issues = []
|
|
if status["motion_count"] == 0:
|
|
issues.append("No motions in database")
|
|
if status["svd_window_count"] == 0:
|
|
issues.append("No SVD windows computed")
|
|
|
|
# Step 3: Suggest remediation
|
|
suggestions = []
|
|
if "No motions in database" in issues:
|
|
suggestions.append("Run pipeline ingestion stage")
|
|
if "No SVD windows computed" in issues:
|
|
suggestions.append("Run SVD computation after ingestion")
|
|
|
|
assert isinstance(issues, list)
|
|
assert isinstance(suggestions, list)
|
|
# Empty DB should produce actionable suggestions
|
|
assert len(suggestions) > 0
|
|
|