From 05c2480ac453fb203554068839c05bd582f268ce Mon Sep 17 00:00:00 2001 From: Bill Date: Sat, 1 Nov 2025 23:20:50 -0400 Subject: [PATCH] feat(api): add JobManager.add_job_warnings method Store job warnings as JSON array in database. Co-Authored-By: Claude --- api/job_manager.py | 46 ++++++++++++++++++++++++++++------ tests/unit/test_job_manager.py | 29 +++++++++++++++++++++ 2 files changed, 67 insertions(+), 8 deletions(-) diff --git a/api/job_manager.py b/api/job_manager.py index 8dee0fd..818e12c 100644 --- a/api/job_manager.py +++ b/api/job_manager.py @@ -148,7 +148,7 @@ class JobManager: SELECT job_id, config_path, status, date_range, models, created_at, started_at, updated_at, completed_at, - total_duration_seconds, error + total_duration_seconds, error, warnings FROM jobs WHERE job_id = ? """, (job_id,)) @@ -168,7 +168,8 @@ class JobManager: "updated_at": row[7], "completed_at": row[8], "total_duration_seconds": row[9], - "error": row[10] + "error": row[10], + "warnings": row[11] } finally: @@ -189,7 +190,7 @@ class JobManager: SELECT job_id, config_path, status, date_range, models, created_at, started_at, updated_at, completed_at, - total_duration_seconds, error + total_duration_seconds, error, warnings FROM jobs ORDER BY created_at DESC LIMIT 1 @@ -210,7 +211,8 @@ class JobManager: "updated_at": row[7], "completed_at": row[8], "total_duration_seconds": row[9], - "error": row[10] + "error": row[10], + "warnings": row[11] } finally: @@ -236,7 +238,7 @@ class JobManager: SELECT job_id, config_path, status, date_range, models, created_at, started_at, updated_at, completed_at, - total_duration_seconds, error + total_duration_seconds, error, warnings FROM jobs WHERE date_range = ? ORDER BY created_at DESC @@ -258,7 +260,8 @@ class JobManager: "updated_at": row[7], "completed_at": row[8], "total_duration_seconds": row[9], - "error": row[10] + "error": row[10], + "warnings": row[11] } finally: @@ -327,6 +330,32 @@ class JobManager: finally: conn.close() + def add_job_warnings(self, job_id: str, warnings: List[str]) -> None: + """ + Store warnings for a job. + + Args: + job_id: Job UUID + warnings: List of warning messages + """ + conn = get_db_connection(self.db_path) + cursor = conn.cursor() + + try: + warnings_json = json.dumps(warnings) + + cursor.execute(""" + UPDATE jobs + SET warnings = ? + WHERE job_id = ? + """, (warnings_json, job_id)) + + conn.commit() + logger.info(f"Added {len(warnings)} warnings to job {job_id}") + + finally: + conn.close() + def update_job_detail_status( self, job_id: str, @@ -575,7 +604,7 @@ class JobManager: SELECT job_id, config_path, status, date_range, models, created_at, started_at, updated_at, completed_at, - total_duration_seconds, error + total_duration_seconds, error, warnings FROM jobs WHERE status IN ('pending', 'running') ORDER BY created_at DESC @@ -594,7 +623,8 @@ class JobManager: "updated_at": row[7], "completed_at": row[8], "total_duration_seconds": row[9], - "error": row[10] + "error": row[10], + "warnings": row[11] }) return jobs diff --git a/tests/unit/test_job_manager.py b/tests/unit/test_job_manager.py index 5d9aa9c..96ab0c4 100644 --- a/tests/unit/test_job_manager.py +++ b/tests/unit/test_job_manager.py @@ -419,4 +419,33 @@ class TestJobUpdateOperations: assert detail["duration_seconds"] > 0 +@pytest.mark.unit +class TestJobWarnings: + """Test job warnings management.""" + + def test_add_job_warnings(self, clean_db): + """Test adding warnings to a job.""" + from api.job_manager import JobManager + from api.database import initialize_database + + initialize_database(clean_db) + job_manager = JobManager(db_path=clean_db) + + # Create a job + job_id = job_manager.create_job( + config_path="config.json", + date_range=["2025-10-01"], + models=["gpt-5"] + ) + + # Add warnings + warnings = ["Rate limit reached", "Skipped 2 dates"] + job_manager.add_job_warnings(job_id, warnings) + + # Verify warnings were stored + job = job_manager.get_job(job_id) + stored_warnings = json.loads(job["warnings"]) + assert stored_warnings == warnings + + # Coverage target: 95%+ for api/job_manager.py