diff --git a/mcp-server/src/legal_mcp/services/db.py b/mcp-server/src/legal_mcp/services/db.py index 7575286..c0eecca 100644 --- a/mcp-server/src/legal_mcp/services/db.py +++ b/mcp-server/src/legal_mcp/services/db.py @@ -7311,6 +7311,21 @@ async def create_missing_precedent( return _row_to_missing_precedent(row) +# Provenance columns for the "צוטט ע״י" display (#148): for a non-appeal gap the +# cited_in_case_id is NULL, so we surface where it actually surfaced from — +# cited_by_precedents (corpus precedents that cite a cited_only stub, via the +# citation graph) and yomon_number (parsed from a digest gap's notes). Shared by +# the list and detail queries so both render identically (G2). +_MP_PROVENANCE_COLS = """, + (SELECT array_agg(DISTINCT src.case_number ORDER BY src.case_number) + FROM precedent_internal_citations pic + JOIN case_law src ON src.id = pic.source_case_law_id + WHERE pic.cited_case_law_id = mp.linked_case_law_id + AND COALESCE(src.case_number, '') <> '' + ) AS cited_by_precedents, + substring(mp.notes from 'מס''?\\s*([0-9]+)') AS yomon_number""" + + async def list_missing_precedents( status: str | None = None, case_id: UUID | None = None, @@ -7355,7 +7370,7 @@ async def list_missing_precedents( SELECT mp.*, c.case_number AS cited_in_case_number, cl.case_number AS linked_case_law_number, - cl.case_name AS linked_case_law_name + cl.case_name AS linked_case_law_name{_MP_PROVENANCE_COLS} FROM missing_precedents mp LEFT JOIN cases c ON c.id = mp.cited_in_case_id LEFT JOIN case_law cl ON cl.id = mp.linked_case_law_id @@ -7379,11 +7394,11 @@ async def get_missing_precedent(mp_id: UUID) -> dict | None: pool = await get_pool() async with pool.acquire() as conn: row = await conn.fetchrow( - """ + f""" SELECT mp.*, c.case_number AS cited_in_case_number, cl.case_number AS linked_case_law_number, - cl.case_name AS linked_case_law_name + cl.case_name AS linked_case_law_name{_MP_PROVENANCE_COLS} FROM missing_precedents mp LEFT JOIN cases c ON c.id = mp.cited_in_case_id LEFT JOIN case_law cl ON cl.id = mp.linked_case_law_id diff --git a/web-ui/src/app/globals.css b/web-ui/src/app/globals.css index fd6ef72..fa07e70 100644 --- a/web-ui/src/app/globals.css +++ b/web-ui/src/app/globals.css @@ -51,6 +51,11 @@ --color-danger-bg: #f5e6e6; --color-info: #4e6a8c; --color-info-bg: #e6ecf3; + /* provenance chips for missing-precedents "צוטט ע״י" (#148, approved mockup 09) */ + --color-plum: #6d5191; + --color-plum-bg: #efe9f6; + --color-teal: #3f7a7a; + --color-teal-bg: #e3efef; /* ── Typography ─────────────────────────────────────── */ --font-sans: var(--font-heebo), -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; diff --git a/web-ui/src/components/missing-precedents/missing-precedents-table.tsx b/web-ui/src/components/missing-precedents/missing-precedents-table.tsx index d1dc157..0ae0399 100644 --- a/web-ui/src/components/missing-precedents/missing-precedents-table.tsx +++ b/web-ui/src/components/missing-precedents/missing-precedents-table.tsx @@ -173,12 +173,44 @@ export function MissingPrecedentsTable({ status, q, legalTopic }: Props) { )} - - {mp.cited_by_party_name ? ( -
- {mp.cited_by_party_name} -
- ) : null} + {mp.discovery_source === "cited_only" ? ( + <> + + פסיקה בקורפוס + + {mp.cited_by_precedents?.length ? ( +
+ מצוטט ע״י: {mp.cited_by_precedents.join(", ")} +
+ ) : null} + + ) : mp.discovery_source === "digest" ? ( + <> + + יומון + + {mp.yomon_number ? ( +
+ מס׳ {mp.yomon_number} +
+ ) : null} + + ) : ( + <> + + {mp.cited_by_party_name ? ( +
+ {mp.cited_by_party_name} +
+ ) : null} + + )}
diff --git a/web-ui/src/lib/api/missing-precedents.ts b/web-ui/src/lib/api/missing-precedents.ts index b1f42f0..12afa3e 100644 --- a/web-ui/src/lib/api/missing-precedents.ts +++ b/web-ui/src/lib/api/missing-precedents.ts @@ -52,6 +52,10 @@ export type MissingPrecedent = { created_at: string; updated_at: string; notes: string | null; + // provenance of the gap (#148) — how it surfaced, for the "צוטט ע״י" column. + discovery_source: string | null; // manual | cited_only | digest | court_fetch + cited_by_precedents: string[] | null; // corpus precedents citing a cited_only stub + yomon_number: string | null; // digest gap's source yomon number }; export type MissingPrecedentListResponse = {