feat(precedents): split library into court rulings + appeals committee tables
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 1m34s

- /api/precedent-library now accepts source_kind param (default external_upload)
- list_external_case_law returns chair_name/district fields
- LibraryListPanel renders two separate tables with appropriate columns
- internal_decisions migration: added queue_halachot param to defer extraction
- Fixed practice_area mapping from style_corpus (appeals_committee → proper enum)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-04 18:49:32 +00:00
parent 92a2763b86
commit c0f67ab841
5 changed files with 221 additions and 129 deletions

View File

@@ -1982,10 +1982,11 @@ async def list_external_case_law(
search: str = "",
limit: int = 100,
offset: int = 0,
source_kind: str = "external_upload",
) -> list[dict]:
"""List chair-uploaded precedents, with simple filters."""
pool = await get_pool()
conditions = ["source_kind = 'external_upload'"]
conditions = [f"source_kind = '{source_kind}'"]
params: list = []
idx = 1
if practice_area:
@@ -2017,6 +2018,7 @@ async def list_external_case_law(
SELECT id, case_number, case_name, court, date, practice_area,
appeal_subtype, source_type, precedent_level, is_binding,
summary, headnote, subject_tags, source_kind,
chair_name, district,
extraction_status, halacha_extraction_status,
metadata_extraction_requested_at,
halacha_extraction_requested_at,

View File

@@ -85,6 +85,7 @@ async def ingest_internal_decision(
file_path: str | Path | None = None,
text: str | None = None,
document_id: UUID | None = None,
queue_halachot: bool = True,
) -> dict:
"""Ingest an appeals-committee decision into the internal corpus.
@@ -158,7 +159,8 @@ async def ingest_internal_decision(
await db.set_case_law_extraction_status(case_law_id, "completed")
await db.set_case_law_halacha_status(case_law_id, "pending")
await db.request_halacha_extraction(case_law_id)
if queue_halachot:
await db.request_halacha_extraction(case_law_id)
return {
"status": "completed",
@@ -173,7 +175,7 @@ async def ingest_internal_decision(
raise
async def migrate_from_style_corpus(dry_run: bool = False) -> dict:
async def migrate_from_style_corpus(dry_run: bool = False, queue_halachot: bool = True) -> dict:
"""Re-index all style_corpus entries as searchable internal committee decisions.
Does NOT delete style_corpus rows — they remain for style analysis.
@@ -211,16 +213,27 @@ async def migrate_from_style_corpus(dry_run: bool = False) -> dict:
try:
subject_tags = list(row["subject_categories"] or [])
raw_pa = row["practice_area"] or ""
subtype = row["appeal_subtype"] or ""
# style_corpus stores 'appeals_committee' (source_type) instead of practice_area
_subtype_to_pa = {
"building_permit": "rishuy_uvniya",
"betterment_levy": "betterment_levy",
"compensation_197": "compensation_197",
}
practice_area = raw_pa if raw_pa in ("rishuy_uvniya", "betterment_levy", "compensation_197") \
else _subtype_to_pa.get(subtype, "")
await ingest_internal_decision(
case_number=case_number,
court="ועדת הערר לתכנון ובנייה — מחוז ירושלים",
decision_date=row["decision_date"],
chair_name="דפנה תמיר",
district="ירושלים",
practice_area=row["practice_area"] or "",
appeal_subtype=row["appeal_subtype"] or "",
practice_area=practice_area,
appeal_subtype=subtype,
subject_tags=subject_tags,
text=row["full_text"],
queue_halachot=queue_halachot,
)
results["ingested"] += 1
logger.info("Migrated style_corpus entry: %s", case_number)