From 72c4593e74adb3c080b065634b36bd3711e1a948 Mon Sep 17 00:00:00 2001 From: Chaim Date: Sun, 3 May 2026 16:39:24 +0000 Subject: [PATCH] fix(precedents): auto-clear *_requested_at on terminal status MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit set_case_law_extraction_status and set_case_law_halacha_status now NULL the corresponding *_requested_at timestamp when status transitions to "completed" or "failed". Without this, completed rows kept lingering in the local-MCP work queue (which scans by `WHERE *_requested_at IS NOT NULL`) and the UI's isPrecedentActive check, leaving them undeletable until a manual SQL cleanup. The pre-existing process_pending_extractions path already called clear_extraction_request, but other paths (re-extraction, status set during upload) didn't — so the cleanup belongs at the status setter. Co-Authored-By: Claude Opus 4.7 (1M context) --- mcp-server/src/legal_mcp/services/db.py | 38 +++++++++++++++++++------ 1 file changed, 30 insertions(+), 8 deletions(-) diff --git a/mcp-server/src/legal_mcp/services/db.py b/mcp-server/src/legal_mcp/services/db.py index 7428bfb..c827f25 100644 --- a/mcp-server/src/legal_mcp/services/db.py +++ b/mcp-server/src/legal_mcp/services/db.py @@ -1774,19 +1774,41 @@ async def update_case_law(case_law_id: UUID, **fields) -> dict | None: async def set_case_law_extraction_status(case_law_id: UUID, status: str) -> None: + """Set text-extraction status. When transitioning to a terminal state + ('completed'/'failed') we also NULL ``metadata_extraction_requested_at`` + so the local-MCP queue (`process_pending_extractions`, which scans by + ``WHERE *_requested_at IS NOT NULL``) doesn't re-pick the row forever + and leave the row blocked in the UI's `isPrecedentActive` check.""" pool = await get_pool() - await pool.execute( - "UPDATE case_law SET extraction_status = $2 WHERE id = $1", - case_law_id, status, - ) + if status in ("completed", "failed"): + await pool.execute( + "UPDATE case_law SET extraction_status = $2, " + "metadata_extraction_requested_at = NULL WHERE id = $1", + case_law_id, status, + ) + else: + await pool.execute( + "UPDATE case_law SET extraction_status = $2 WHERE id = $1", + case_law_id, status, + ) async def set_case_law_halacha_status(case_law_id: UUID, status: str) -> None: + """Set halacha-extraction status. Mirrors ``set_case_law_extraction_status``: + on terminal states we also clear ``halacha_extraction_requested_at`` so the + queue and UI don't see a stale request flag.""" pool = await get_pool() - await pool.execute( - "UPDATE case_law SET halacha_extraction_status = $2 WHERE id = $1", - case_law_id, status, - ) + if status in ("completed", "failed"): + await pool.execute( + "UPDATE case_law SET halacha_extraction_status = $2, " + "halacha_extraction_requested_at = NULL WHERE id = $1", + case_law_id, status, + ) + else: + await pool.execute( + "UPDATE case_law SET halacha_extraction_status = $2 WHERE id = $1", + case_law_id, status, + ) async def list_external_case_law(