fix(#78): trigger extraction wakeup on committee-decision upload + surface failures

The /api/internal-decisions/upload path (used by the UI for ועדת-ערר
decisions) never called pc_wake_for_precedent_extraction, so committee
decisions were stuck at halacha_extraction_status='pending' forever — the
CEO was never woken to drain the queue. Root cause behind 8027-25's stuck
extraction. The other two upload paths (precedent_library, missing-precedent)
already wake the CEO; this one was missing it.

- internal-decisions upload: add the wakeup, routing the company by case
  number prefix (1xxx→רישוי, 8xxx→היטל, 9xxx→פיצויים) when practice_area is
  empty (else an 8xxx case wrongly routes to the licensing CEO).
- all three call sites: the wake helper returns {ok:False} WITHOUT raising
  on a skipped/failed wakeup; that was silently dropped. Now logged at
  WARNING with the reason, and the upload progress carries extraction_queued.

Fallback drainer (scheduled precedent_process_pending) deferred — the
missing wakeup was the actual failure; manual precedent_process_pending
remains the recovery path.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-02 12:06:31 +00:00
parent 7471dcf3cc
commit 1d3e235556

View File

@@ -5253,11 +5253,21 @@ async def precedent_library_upload(
case_law_id = result.get("case_law_id") if isinstance(result, dict) else None
if case_law_id:
try:
await pc_wake_for_precedent_extraction(
wake = await pc_wake_for_precedent_extraction(
case_law_id=case_law_id,
citation=citation.strip(),
practice_area=practice_area,
)
# The wake helper returns {ok: False, ...} on a skipped /
# failed wakeup WITHOUT raising — previously that path was
# silently dropped and the precedent sat at 'pending'
# forever. Surface it as a WARNING with the reason.
if not wake.get("ok"):
logger.warning(
"precedent %s: extraction wakeup did not queue (%s) — "
"halachot stay pending until precedent_process_pending runs",
case_law_id, wake.get("skipped") or wake.get("error"),
)
except Exception:
logger.exception("precedent-extraction wakeup failed (non-fatal)")
except Exception as e:
@@ -5524,7 +5534,7 @@ async def internal_decisions_upload(
async def _run():
try:
await int_decisions_service.ingest_internal_decision(
result = await int_decisions_service.ingest_internal_decision(
case_number=case_number.strip(),
case_name=case_name.strip(),
court=court.strip(),
@@ -5538,7 +5548,40 @@ async def internal_decisions_upload(
summary=summary.strip(),
file_path=staged,
)
await _progress.set(task_id, {"status": "completed", "percent": 100})
# Auto-trigger halacha+metadata extraction via the CEO. The
# extractor needs the local `claude` CLI (absent in this
# container), so the only automatic path is a Paperclip wakeup.
# Without this, committee decisions stay stuck forever at
# halacha_extraction_status='pending' (the other two upload paths
# — precedent_library_upload and missing-precedent — already do
# this; this path was missing it).
case_law_id = result.get("case_law_id") if isinstance(result, dict) else None
extraction_queued = True
if case_law_id:
# Route to the correct company CEO. _get_company_id keys off
# practice_area; committee case numbers are reliably prefixed
# (1xxx→רישוי, 8xxx→היטל, 9xxx→פיצויים), so derive a routing
# tag from the prefix when practice_area is empty — otherwise
# an 8xxx case wrongly routes to the licensing CEO.
routing_pa = practice_area or {
"1": "rishuy_uvniya", "8": "betterment_levy", "9": "compensation_197",
}.get(case_number.strip()[:1], "")
wake = await pc_wake_for_precedent_extraction(
case_law_id=case_law_id,
citation=case_number.strip(),
practice_area=routing_pa,
)
if not wake.get("ok"):
extraction_queued = False
logger.warning(
"internal-decision %s: extraction wakeup did not queue (%s) — "
"halachot stay pending until precedent_process_pending runs",
case_number, wake.get("skipped") or wake.get("error"),
)
await _progress.set(task_id, {
"status": "completed", "percent": 100,
"extraction_queued": extraction_queued,
})
except Exception as e:
logger.exception("internal-decisions upload failed")
await _progress.set(task_id, {"status": "failed", "error": str(e)})
@@ -6023,11 +6066,20 @@ async def missing_precedent_upload(
# file's text. Best-effort: mirrors the precedent_library_upload
# contract — failures are logged, not surfaced.
try:
await pc_wake_for_precedent_extraction(
routing_pa = practice_area or {
"1": "rishuy_uvniya", "8": "betterment_levy", "9": "compensation_197",
}.get(committee_case_number.strip()[:1], "") if is_committee else practice_area
wake = await pc_wake_for_precedent_extraction(
case_law_id=case_law_id,
citation=citation,
practice_area=practice_area,
practice_area=routing_pa,
)
if not wake.get("ok"):
logger.warning(
"missing-precedent %s: extraction wakeup did not queue (%s) — "
"halachot stay pending until precedent_process_pending runs",
case_law_id, wake.get("skipped") or wake.get("error"),
)
except Exception:
logger.exception(
"missing-precedent: precedent-extraction wakeup failed (non-fatal)"