fix(precedents): מראה-מקום never blank — seed at upload + inline Gemini enrichment (root cause)
Root cause: the upload form "מראה המקום" field is stored only as case_number; citation_formatted was left empty and filled ONLY by the async metadata extraction, which runs in the local drainer (not the container) because it was lumped with halacha extraction. Result: the chair saw an empty מראה-מקום during the window and re-typed it by hand. Fix (hybrid — Option C): - Seed: _create_external_record / create_external_case_law store the chair's typed citation as citation_formatted at INSERT, so the field is never blank. A cited_only→external promotion preserves an existing non-empty value (prior edit). - Enrich: ingest_precedent runs metadata extraction INLINE in-container (gemini_session is direct REST, no local CLI) with force_citation=True, upgrading the seed to the canonical derived citation (parties + reporter + date) before the chair opens the page. Best-effort: on no key / API failure the seed remains and the queued metadata drain stays as the fallback. Halacha extraction is untouched (stays local — claude_session). - apply_to_record / extract_and_apply gain force_citation: re-assemble even when citation_formatted is non-empty, writing only when assembly SUCCEEDS (seed preserved on abstention). The drainer keeps the default (False) so a chair's manual edit in /precedents/[id] is never clobbered. Ops: GOOGLE_GEMINI_API_KEY added to the legal-ai Coolify app (runtime) — the SoT value from Infisical nautilus:/external-apis/gemini, validated against the API. Invariants: G2 (one citation-resolution + one metadata-extraction path, reused — no parallel logic), INV-ID2/X1§3 (citation_formatted stays a derived field; the seed is provisional and upgraded), INV-G10 (chair edits preserved). No schema change. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -4334,12 +4334,19 @@ async def create_external_case_law(
|
||||
precedent_level: str = "",
|
||||
is_binding: bool = True,
|
||||
document_id: UUID | None = None,
|
||||
citation_formatted: str = "",
|
||||
) -> dict:
|
||||
"""Insert a chair-uploaded external precedent into case_law.
|
||||
|
||||
If a row with this ``case_number`` already exists with
|
||||
source_kind='cited_only' (auto-discovered), promote it to
|
||||
source_kind='external_upload' and fill in the missing fields.
|
||||
|
||||
``citation_formatted`` seeds the מראה-מקום from the chair's typed upload-form
|
||||
value so the field is NEVER blank between upload and metadata extraction (the
|
||||
inline enrichment later UPGRADES it to the canonical derived form via
|
||||
``apply_to_record(force_citation=True)``). On a cited_only→external promotion
|
||||
an existing non-empty value (a prior chair edit) is preserved.
|
||||
"""
|
||||
# INV-DM7: an appeals-committee source is persuasive even when uploaded via
|
||||
# the external path — coerce to non-binding so it matches the committee
|
||||
@@ -4364,11 +4371,12 @@ async def create_external_case_law(
|
||||
summary, key_quote, full_text, source_url,
|
||||
source_kind, document_id, extraction_status,
|
||||
halacha_extraction_status, practice_area, appeal_subtype,
|
||||
headnote, source_type, precedent_level, is_binding, content_hash
|
||||
headnote, source_type, precedent_level, is_binding, content_hash,
|
||||
citation_formatted
|
||||
) VALUES (
|
||||
$1, $2, $3, $4, $5, $6, $7, $8, $9,
|
||||
'external_upload', $10, 'processing', 'pending',
|
||||
$11, $12, $13, $14, $15, $16, $17
|
||||
$11, $12, $13, $14, $15, $16, $17, $18
|
||||
)
|
||||
ON CONFLICT (case_number) WHERE source_kind <> 'internal_committee'
|
||||
DO UPDATE SET
|
||||
@@ -4390,14 +4398,16 @@ async def create_external_case_law(
|
||||
source_kind = 'external_upload',
|
||||
extraction_status = 'processing',
|
||||
halacha_extraction_status = 'pending',
|
||||
content_hash = EXCLUDED.content_hash
|
||||
content_hash = EXCLUDED.content_hash,
|
||||
citation_formatted = COALESCE(
|
||||
NULLIF(case_law.citation_formatted, ''), EXCLUDED.citation_formatted)
|
||||
RETURNING *
|
||||
""",
|
||||
case_number, case_name, court, decision_date, tags_json,
|
||||
summary, key_quote, full_text, source_url,
|
||||
document_id, practice_area, appeal_subtype, headnote,
|
||||
source_type, precedent_level, is_binding,
|
||||
_content_hash(full_text),
|
||||
_content_hash(full_text), (citation_formatted or "").strip(),
|
||||
)
|
||||
return _row_to_case_law(row)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user