diff --git a/web-ui/src/components/goldset/goldset-panel.tsx b/web-ui/src/components/goldset/goldset-panel.tsx index 79f8265..6b2450c 100644 --- a/web-ui/src/components/goldset/goldset-panel.tsx +++ b/web-ui/src/components/goldset/goldset-panel.tsx @@ -1,7 +1,7 @@ "use client"; import { useEffect, useMemo, useState } from "react"; -import { Check, X, ChevronDown, ChevronLeft, Info } from "lucide-react"; +import { Check, X, ChevronDown, ChevronLeft, Info, AlertTriangle } from "lucide-react"; import { toast } from "sonner"; import { Button } from "@/components/ui/button"; import { Badge } from "@/components/ui/badge"; @@ -21,6 +21,23 @@ const TYPES: { value: string; label: string }[] = [ { value: "persuasive", label: "משכנע" }, ]; +// Consistency between is_holding and the type (#81.7): a real holding is +// binding/interpretive/procedural/persuasive; a NON-holding is its reason — +// application (fact-bound) or obiter (not decided). Other pairings contradict. +const HOLDING_TYPES = new Set(["binding", "interpretive", "procedural", "persuasive"]); +const NON_HOLDING_TYPES = new Set(["application", "obiter"]); + +function inconsistentTag(it: GoldsetItem): string | null { + if (it.is_holding === null || !it.correct_type) return null; + if (it.is_holding === true && NON_HOLDING_TYPES.has(it.correct_type)) { + return "סימנת \"הלכה\" אך הסוג הוא יישום/אמרת-אגב — אלה דווקא הסיבות שמשהו אינו הלכה."; + } + if (it.is_holding === false && HOLDING_TYPES.has(it.correct_type)) { + return "סימנת \"לא הלכה\" אך הסוג מציין הלכה (מחייבת/פרשני/…); ל\"לא\" מתאים יישום או אמרת-אגב."; + } + return null; +} + const FLAG_LABELS: Record = { non_decision: "אי-הכרעה", truncated_quote: "ציטוט קטוע", thin_restatement: "ניסוח דק", quote_unverified: "ציטוט לא מאומת", nli_unsupported: "כלל לא נגזר", application: "יישום", @@ -232,6 +249,12 @@ function TagCard({ onClick={() => onTag({ correct_type: t.value })}>{t.label} ))} + {inconsistentTag(it) && ( +

+ + {inconsistentTag(it)} +

+ )} {/* quote_complete */}