Merge pull request 'feat(web-ui): X11 corroboration badge on halachot' (#35) from feat/x11-corroboration-web-ui into main
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 1m35s
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 1m35s
This commit was merged in pull request #35.
This commit is contained in:
@@ -3406,9 +3406,23 @@ async def list_halachot(
|
|||||||
h.cites, h.confidence, h.quote_verified, h.review_status,
|
h.cites, h.confidence, h.quote_verified, h.review_status,
|
||||||
h.reviewer, h.reviewed_at, h.created_at, h.updated_at,
|
h.reviewer, h.reviewed_at, h.created_at, h.updated_at,
|
||||||
cl.case_number, cl.case_name, cl.court, cl.date AS decision_date,
|
cl.case_number, cl.case_name, cl.court, cl.date AS decision_date,
|
||||||
cl.precedent_level
|
cl.precedent_level,
|
||||||
|
COALESCE(cor.corroboration_count, 0)::int AS corroboration_count,
|
||||||
|
COALESCE(cor.corroboration_negative, false) AS corroboration_negative
|
||||||
FROM halachot h
|
FROM halachot h
|
||||||
LEFT JOIN case_law cl ON cl.id = h.case_law_id
|
LEFT JOIN case_law cl ON cl.id = h.case_law_id
|
||||||
|
LEFT JOIN (
|
||||||
|
SELECT halacha_id,
|
||||||
|
count(DISTINCT COALESCE(citing_case_law_id::text,
|
||||||
|
citing_decision_id::text, source_citation_id::text))
|
||||||
|
FILTER (WHERE treatment IN ('followed','explained'))
|
||||||
|
AS corroboration_count,
|
||||||
|
bool_or(treatment IN
|
||||||
|
('distinguished','criticized','questioned','overruled'))
|
||||||
|
AS corroboration_negative
|
||||||
|
FROM halacha_citation_corroboration
|
||||||
|
GROUP BY halacha_id
|
||||||
|
) cor ON cor.halacha_id = h.id
|
||||||
{where_sql}
|
{where_sql}
|
||||||
ORDER BY h.case_law_id, h.halacha_index
|
ORDER BY h.case_law_id, h.halacha_index
|
||||||
LIMIT ${idx} OFFSET ${idx + 1}
|
LIMIT ${idx} OFFSET ${idx + 1}
|
||||||
|
|||||||
51
web-ui/src/components/precedents/corroboration-badge.tsx
Normal file
51
web-ui/src/components/precedents/corroboration-badge.tsx
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
import { Scale, AlertTriangle } from "lucide-react";
|
||||||
|
import { Badge } from "@/components/ui/badge";
|
||||||
|
import type { Halacha } from "@/lib/api/precedent-library";
|
||||||
|
|
||||||
|
/* X11 — citation corroboration signal for a halacha.
|
||||||
|
*
|
||||||
|
* Shows how many distinct later courts/committees adopted this halacha
|
||||||
|
* (positive treatment). ≥2 distinct positive sources = "מתוקף" (the
|
||||||
|
* auto-approve threshold, INV-COR4); a single citation is shown more
|
||||||
|
* softly. A negative treatment (distinguished/criticized/overruled) is
|
||||||
|
* surfaced as a warning — those never auto-approve and an overruled one
|
||||||
|
* is sent back to the chair gate (INV-COR2). Renders nothing when there
|
||||||
|
* is no citation signal at all. */
|
||||||
|
export function CorroborationBadge({ halacha }: { halacha: Halacha }) {
|
||||||
|
const count = halacha.corroboration_count ?? 0;
|
||||||
|
const negative = halacha.corroboration_negative ?? false;
|
||||||
|
|
||||||
|
if (negative) {
|
||||||
|
return (
|
||||||
|
<Badge
|
||||||
|
variant="outline"
|
||||||
|
className="text-[0.65rem] bg-danger-bg text-danger border-danger/40"
|
||||||
|
title="ערכאה/ועדה מאוחרת אבחנה, מתחה ביקורת או ביטלה הלכה זו — אינה מאושרת אוטומטית בתיקוף-ציטוטים (X11)"
|
||||||
|
>
|
||||||
|
<AlertTriangle className="w-3 h-3 me-1" /> טיפול שלילי בציטוט
|
||||||
|
</Badge>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count <= 0) return null;
|
||||||
|
|
||||||
|
const corroborated = count >= 2;
|
||||||
|
return (
|
||||||
|
<Badge
|
||||||
|
variant="outline"
|
||||||
|
className={
|
||||||
|
corroborated
|
||||||
|
? "text-[0.65rem] bg-gold-wash text-gold-deep border-gold/40 tabular-nums"
|
||||||
|
: "text-[0.65rem] bg-rule-soft text-ink-muted tabular-nums"
|
||||||
|
}
|
||||||
|
title={
|
||||||
|
corroborated
|
||||||
|
? `מתוקף ע"י ${count} ערכאות/ועדות מאוחרות שאימצו הלכה זו (טיפול שיפוטי מצטבר, X11)`
|
||||||
|
: "ציטוט מאמת בודד — מתחת לסף התיקוף (נדרשים ≥2 מקורות בלתי-תלויים, X11)"
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Scale className="w-3 h-3 me-1" />
|
||||||
|
{corroborated ? `מתוקף · ${count} ציטוטים` : "ציטוט מאמת · 1"}
|
||||||
|
</Badge>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
import { useMemo, useState } from "react";
|
import { useMemo, useState } from "react";
|
||||||
import { Badge } from "@/components/ui/badge";
|
import { Badge } from "@/components/ui/badge";
|
||||||
|
import { CorroborationBadge } from "@/components/precedents/corroboration-badge";
|
||||||
import type { Halacha } from "@/lib/api/precedent-library";
|
import type { Halacha } from "@/lib/api/precedent-library";
|
||||||
|
|
||||||
const RULE_TYPE_LABELS: Record<string, string> = {
|
const RULE_TYPE_LABELS: Record<string, string> = {
|
||||||
@@ -148,6 +149,7 @@ export function ExtractedHalachotSection({ halachot }: { halachot: Halacha[] })
|
|||||||
<Badge variant="outline" className="text-[0.65rem] tabular-nums">
|
<Badge variant="outline" className="text-[0.65rem] tabular-nums">
|
||||||
ביטחון {h.confidence.toFixed(2)}
|
ביטחון {h.confidence.toFixed(2)}
|
||||||
</Badge>
|
</Badge>
|
||||||
|
<CorroborationBadge halacha={h} />
|
||||||
{h.page_reference ? (
|
{h.page_reference ? (
|
||||||
<span className="text-[0.7rem] text-ink-muted ms-auto">
|
<span className="text-[0.7rem] text-ink-muted ms-auto">
|
||||||
{h.page_reference}
|
{h.page_reference}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import { Button } from "@/components/ui/button";
|
|||||||
import { Badge } from "@/components/ui/badge";
|
import { Badge } from "@/components/ui/badge";
|
||||||
import { Skeleton } from "@/components/ui/skeleton";
|
import { Skeleton } from "@/components/ui/skeleton";
|
||||||
import { Textarea } from "@/components/ui/textarea";
|
import { Textarea } from "@/components/ui/textarea";
|
||||||
|
import { CorroborationBadge } from "./corroboration-badge";
|
||||||
import { practiceAreaLabel } from "./practice-area";
|
import { practiceAreaLabel } from "./practice-area";
|
||||||
import {
|
import {
|
||||||
useHalachotPending, useUpdateHalacha, type Halacha,
|
useHalachotPending, useUpdateHalacha, type Halacha,
|
||||||
@@ -115,6 +116,7 @@ function HalachaCard({
|
|||||||
<Badge variant="outline" className="text-[0.65rem]">
|
<Badge variant="outline" className="text-[0.65rem]">
|
||||||
{ruleTypeLabel(h.rule_type)}
|
{ruleTypeLabel(h.rule_type)}
|
||||||
</Badge>
|
</Badge>
|
||||||
|
<CorroborationBadge halacha={h} />
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -83,6 +83,11 @@ export type Halacha = {
|
|||||||
court?: string;
|
court?: string;
|
||||||
decision_date?: string | null;
|
decision_date?: string | null;
|
||||||
precedent_level?: string;
|
precedent_level?: string;
|
||||||
|
/* X11 citation corroboration — how many distinct later courts/committees
|
||||||
|
* adopted this halacha (positive treatment), and whether any cited it
|
||||||
|
* negatively (distinguished/criticized/overruled). */
|
||||||
|
corroboration_count?: number;
|
||||||
|
corroboration_negative?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type RelatedCase = {
|
export type RelatedCase = {
|
||||||
|
|||||||
Reference in New Issue
Block a user