Merge pull request 'refactor(digests): single source of truth — drop processed/ folder state (X12)' (#122) from worktree-digests-single-truth into main
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 28s

This commit was merged in pull request #122.
This commit is contained in:
2026-06-07 20:33:43 +00:00
3 changed files with 14 additions and 11 deletions

View File

@@ -90,7 +90,7 @@
| `run_curator_sonnet_rerun.sh` | A/B test #3 (2026-05-05) — ריצה חוזרת של Sonnet 4.5 על אותו CMP-78. תוצאה: 12:52 דק׳ (לעומת 20:13 בריצה המקורית — כי בלי לולאת interaction.json). זיהה תוצאה שגויה ("דחייה") **בעקביות עם הריצה המקורית** — Sonnet עקבי-בטעות, DeepSeek אקראי. | בדיקה חד-פעמית — לא להריץ שוב |
| `ingest_incoming_batch.py` | python | קליטת batch של החלטות ועדת ערר מ-`data/precedents/incoming/` דרך המסלול הקנוני (`ingest_internal_decision`) + חילוץ מטא-דאטה לכל תיק (המסלול הפנימי לא מתזמן metadata — INV-ING3). רצף (לא מקבילי, להימנע מעומס CLI). רשימת `DECISIONS` נערכת ידנית לכל batch. config מ-`~/.env`. תומך תהליך [[project_precedent_incoming_workflow]]. | ידני, per-batch (חלופה ל-MCP `internal_decision_upload` כש-batch גדול) |
| `drain_halacha_queue.py` | python | ריקון תור חילוץ ההלכות (`process_pending_extractions kind='halacha'`) ב-batches של 4 עד שהתור ריק (2 סבבים ריקים). משמש אחרי `ingest_incoming_batch.py`. | ידני אחרי batch (חלופה ל-MCP `precedent_process_pending`) |
| `ingest_digests_batch.py` | python | קליטת batch של יומוני "כל יום" מ-`data/digests/incoming/` דרך המסלול העצמאי של קורפוס-הגילוי (`digest_library.ingest_digest`) — חילוץ-LLM (תג-מושג, כותרת-הלכה, מראה-מקום, שני-תאריכים), embedding יחיד, ו-autolink לפסק המקורי (X12/INV-DIG3). רצף (לא מקבילי). מזהה-יומון+תאריך נגזרים משם-הקובץ; העלון החודשי מדולג. קבצים מועברים ל-`processed/`. config מ-`~/.env`. | ידני, per-batch (חלופה ל-MCP `digest_upload`) |
| `ingest_digests_batch.py` | python | קליטת batch של יומוני "כל יום" מ-`data/digests/incoming/` דרך המסלול העצמאי של קורפוס-הגילוי (`digest_library.ingest_digest`) — חילוץ-LLM (תג-מושג, כותרת-הלכה, מראה-מקום, שני-תאריכים), embedding יחיד, ו-autolink לפסק המקורי (X12/INV-DIG3). רצף (לא מקבילי). מזהה-יומון+תאריך נגזרים משם-הקובץ; העלון החודשי מדולג. **לא מעביר קבצים** — ה-DB (content_hash) הוא מקור-האמת היחיד; הרצה חוזרת מדלגת על קיימים (`exists`). config מ-`~/.env`. | ידני, per-batch (חלופה ל-MCP `digest_upload`) |
## סקריפטים שנמחקו (git history בלבד)

View File

@@ -15,6 +15,13 @@ halacha pipeline and is never cited in a decision (INV-DIG1/2). After this run,
relink unmatched digests once the originals are uploaded, or surface them via
missing_precedent_create.
SINGLE SOURCE OF TRUTH: the `digests` table (DB) is the ONLY authority for what
has been ingested. This script does NOT move files between folders — re-running
is safe because ``ingest_digest`` dedups on content_hash (already-ingested →
returns ``exists``). Files left in ``incoming/`` are simply re-checked and
skipped. (Earlier versions moved files to a ``processed/`` folder; that created
a second, divergent state and was removed.)
Yomon number + issue date are parsed from the filename
("יומון 5158 - 31.5.26.pdf") as hints; the LLM also extracts them from the
body and the explicit hint wins. The monthly bulletin (e.g. "201 יוני.pdf") is
@@ -28,7 +35,6 @@ Config (POSTGRES_URL, VOYAGE_API_KEY, ANTHROPIC_API_KEY) auto-loads from ~/.env.
import asyncio
import os
import re
import shutil
import sys
import traceback
from pathlib import Path
@@ -39,7 +45,6 @@ from legal_mcp import config # noqa: E402
from legal_mcp.services import digest_library as svc # noqa: E402
INCOMING = Path(config.DATA_DIR) / "digests" / "incoming"
PROCESSED = Path(config.DATA_DIR) / "digests" / "processed"
# Matches "יומון 5158 - 31.5.26" → ("5158", "31.5.26")
_NAME_RE = re.compile(r"יומון\s*(\d+)\s*-\s*(\d{1,2})\.(\d{1,2})\.(\d{2,4})")
@@ -78,7 +83,6 @@ async def main(argv: list[str]) -> None:
if not files:
print(f"No yomon PDFs found in {INCOMING}", flush=True)
return
PROCESSED.mkdir(parents=True, exist_ok=True)
results = []
for idx, fp in enumerate(files):
@@ -108,11 +112,8 @@ async def main(argv: list[str]) -> None:
f"{link} | {out.get('underlying_citation')}",
flush=True,
)
# Move to processed/ so re-runs are clean (idempotent anyway).
try:
shutil.move(str(fp), str(PROCESSED / fp.name))
except Exception as e:
print(f" (could not move {fp.name}: {e})", flush=True)
# No folder move — the DB (content_hash) is the single source of
# truth. Re-running re-checks incoming/ and skips already-ingested.
except Exception as e:
rec["error"] = f"{type(e).__name__}: {e}"
print(f"{fp.name}: {e}", flush=True)