feat(precedents): formal citation per Israeli citation rules + copy/edit UI
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 3m25s
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 3m25s
Until now, "case_number" was the only stored identifier for a precedent.
But a *citation per the Israeli unified citation rules* is a different
beast — it has bold parties, an unbold prefix (court abbrev + panel/
district parenthetical + case number), and an unbold trailing reporter
(נבו / פ"ד...). Without storing it as a first-class field we couldn't
hand the chair a one-click "copy as citation" experience for pasting
into decisions.
Changes:
- Schema V19: case_law.citation_formatted TEXT (Markdown — parties
wrapped in **…** so the copy helper can render <strong> for Word/Docs
paste and keep plain-text fallback meaningful).
- Metadata extractor: composes citation_formatted from the document
text per the unified citation rules, with worked examples for ע"א /
עת"מ / ערר / בל"מ in the prompt. Refuses to store half-formed strings.
- PATCH /api/precedent-library/{id} accepts citation_formatted so the
chair can correct LLM mistakes.
- /precedents/[id]: dedicated "מראה מקום" block with bold rendering,
a copy-to-clipboard button (text/html + text/plain so Word keeps
the bolds), and an inline edit textarea.
- /precedents list rows: link displays the formatted citation when
available, with a small inline copy button — falls back to the bare
case_number for older rows.
Backfill of existing rows happens by re-stamping the extraction queue
once V19 has rolled out and the new field is reachable.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1007,6 +1007,20 @@ CREATE INDEX IF NOT EXISTS idx_relevance_case_law
|
||||
"""
|
||||
|
||||
|
||||
# ── V19: case_law.citation_formatted ───────────────────────────────
|
||||
# Full formal citation per the Israeli unified citation rules ("כללי
|
||||
# הציטוט האחיד"). Stored as Markdown: parties wrapped in **…** so the
|
||||
# copy-to-clipboard helper can render bold for Word/Docs while keeping
|
||||
# the plain-text form readable.
|
||||
#
|
||||
# Example:
|
||||
# ערר (ועדות ערר - תכנון ובנייה ת"א-יפו) 81002-01-21 **אברהם אגסי
|
||||
# נ' הועדה המקומית לתכנון ובנייה תל אביב** (נבו 25.9.2025)
|
||||
SCHEMA_V19_SQL = """
|
||||
ALTER TABLE case_law ADD COLUMN IF NOT EXISTS citation_formatted TEXT DEFAULT '';
|
||||
"""
|
||||
|
||||
|
||||
async def _run_schema_migrations(pool: asyncpg.Pool) -> None:
|
||||
async with pool.acquire() as conn:
|
||||
await conn.execute(SCHEMA_SQL)
|
||||
@@ -1028,7 +1042,8 @@ async def _run_schema_migrations(pool: asyncpg.Pool) -> None:
|
||||
await conn.execute(SCHEMA_V16_SQL)
|
||||
await conn.execute(SCHEMA_V17_SQL)
|
||||
await conn.execute(SCHEMA_V18_SQL)
|
||||
logger.info("Database schema initialized (v1-v18)")
|
||||
await conn.execute(SCHEMA_V19_SQL)
|
||||
logger.info("Database schema initialized (v1-v19)")
|
||||
|
||||
|
||||
async def init_schema() -> None:
|
||||
@@ -2288,13 +2303,13 @@ async def update_case_law(case_law_id: UUID, **fields) -> dict | None:
|
||||
|
||||
Allowed fields: case_name, court, date, practice_area, appeal_subtype,
|
||||
subject_tags, summary, headnote, key_quote, source_url, source_type,
|
||||
precedent_level, is_binding.
|
||||
precedent_level, is_binding, citation_formatted.
|
||||
"""
|
||||
allowed = {
|
||||
"case_number", "case_name", "court", "date", "practice_area", "appeal_subtype",
|
||||
"subject_tags", "summary", "headnote", "key_quote", "source_url",
|
||||
"source_type", "precedent_level", "is_binding", "district", "chair_name",
|
||||
"proceeding_type",
|
||||
"proceeding_type", "citation_formatted",
|
||||
}
|
||||
updates = {k: v for k, v in fields.items() if k in allowed}
|
||||
if not updates:
|
||||
@@ -2405,7 +2420,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,
|
||||
chair_name, district, citation_formatted,
|
||||
extraction_status, halacha_extraction_status,
|
||||
metadata_extraction_requested_at,
|
||||
halacha_extraction_requested_at,
|
||||
|
||||
Reference in New Issue
Block a user