From cb2dd0b118b47ab10a7c3c725d5395628b846f7a Mon Sep 17 00:00:00 2001 From: Mithali Phadtare Date: Sun, 28 Jun 2026 14:36:51 +0530 Subject: [PATCH] feat: persist patch outcomes across generation and verification stages --- backend/app/db.py | 33 ++++++++++++++++++++++++++++++++- backend/app/main.py | 24 +++++++++++++++++++++++- 2 files changed, 55 insertions(+), 2 deletions(-) diff --git a/backend/app/db.py b/backend/app/db.py index 930d23b..2816aaf 100644 --- a/backend/app/db.py +++ b/backend/app/db.py @@ -88,7 +88,18 @@ async def init_db(): created_at TEXT DEFAULT (datetime('now')) ) """) - + await db.execute(""" + CREATE TABLE IF NOT EXISTS patch_outcomes ( + id TEXT PRIMARY KEY, + job_id TEXT NOT NULL, + finding_id TEXT NOT NULL, + model TEXT NOT NULL, + passed INTEGER, + prompt_tokens INTEGER, + created_at TEXT DEFAULT (datetime('now')), + verified_at TEXT + ) + """) db.row_factory = aiosqlite.Row cursor = await db.execute("PRAGMA table_info(findings)") columns = [row["name"] for row in await cursor.fetchall()] @@ -299,3 +310,23 @@ async def upsert_contributor_stat( (username, findings, fixes, prs), ) await db.commit() + + async def insert_patch_outcome(patch_id: str, job_id: str, finding_id: str, model: str, prompt_tokens: int = None): + """Inserts a new patch record when an LLM generates a fix.""" + async with aiosqlite.connect(DB_PATH) as db: + await db.execute( + "INSERT INTO patch_outcomes (id, job_id, finding_id, model, passed, prompt_tokens) VALUES (?, ?, ?, ?, NULL, ?)", + (patch_id, job_id, finding_id, model, prompt_tokens) + ) + await db.commit() + + +async def update_patch_verification(patch_id: str, passed: bool): + """Updates the verification status and timestamp of an existing patch.""" + passed_int = 1 if passed else 0 + async with aiosqlite.connect(DB_PATH) as db: + await db.execute( + "UPDATE patch_outcomes SET passed = ?, verified_at = datetime('now') WHERE id = ?", + (passed_int, patch_id) + ) + await db.commit() \ No newline at end of file diff --git a/backend/app/main.py b/backend/app/main.py index d88dc1f..79a1a3d 100644 --- a/backend/app/main.py +++ b/backend/app/main.py @@ -751,7 +751,7 @@ async def _record_fixes_to_db(job_id: str, fixes: List[Fix]): @app.post("/fix", response_model=FixResponse) -def fix(req: FixRequest, background_tasks: BackgroundTasks): +async def fix(req: FixRequest, background_tasks: BackgroundTasks): job_dir = WORK_ROOT / req.job_id repo_dir = job_dir / "repo" if not repo_dir.exists(): @@ -760,6 +760,22 @@ def fix(req: FixRequest, background_tasks: BackgroundTasks): repo_dir = _maybe_use_single_top_folder(repo_dir) fixes = propose_fixes(repo_dir, req.finding_ids) + import uuid + from app.db import insert_patch_outcome + + for f_id in req.finding_ids: + patch_id = str(uuid.uuid4()) + model_name = getattr(req, "model", "Ollama-Local") + tokens = getattr(req, "prompt_tokens", None) + + await insert_patch_outcome( + patch_id=patch_id, + job_id=req.job_id, + finding_id=f_id, + model=model_name, + prompt_tokens=tokens + ) + background_tasks.add_task(_record_fixes_to_db, req.job_id, fixes) return FixResponse(job_id=req.job_id, fixes=fixes) @@ -846,6 +862,12 @@ async def verify( ), ) await db.commit() + + # --- UPDATE THE PATCH OUTCOMES TRACKING TABLE --- + from app.db import update_patch_verification + await update_patch_verification(patch_id=job_id, passed=bool(passed)) + # ------------------------------------------------ + finally: await db.close() except Exception: