diff --git a/mcp-server/src/legal_mcp/services/db.py b/mcp-server/src/legal_mcp/services/db.py
index ca38047..2f6369f 100644
--- a/mcp-server/src/legal_mcp/services/db.py
+++ b/mcp-server/src/legal_mcp/services/db.py
@@ -4340,7 +4340,7 @@ async def goldset_list(batch: str = "default") -> list[dict]:
" g.correct_type, g.quote_complete, g.tagged_by, g.tagged_at, "
" h.rule_statement, h.supporting_quote, h.reasoning_summary, "
" h.rule_type, h.confidence, h.quality_flags, h.review_status, "
- " cl.case_number, cl.case_name "
+ " cl.case_number, cl.case_name, cl.source_type "
"FROM halacha_goldset g JOIN halachot h ON h.id = g.halacha_id "
"LEFT JOIN case_law cl ON cl.id = h.case_law_id "
"WHERE g.batch = $1 ORDER BY g.created_at, g.id", batch,
diff --git a/web-ui/src/components/goldset/goldset-panel.tsx b/web-ui/src/components/goldset/goldset-panel.tsx
index 280db66..1daa656 100644
--- a/web-ui/src/components/goldset/goldset-panel.tsx
+++ b/web-ui/src/components/goldset/goldset-panel.tsx
@@ -49,6 +49,17 @@ function cleanCitation(s: string | null | undefined): string {
return s.replace(/[--]/g, "").trim();
}
+// Source separation (פסקי-דין מול החלטות ועדת-ערר) for convenient tagging.
+function sourceLabel(s: string | null): string {
+ return s === "court_ruling" ? "פסק-דין"
+ : s === "appeals_committee" ? "ועדת ערר" : "אחר";
+}
+const SOURCE_FILTERS: { value: "all" | "court_ruling" | "appeals_committee"; label: string }[] = [
+ { value: "all", label: "הכל" },
+ { value: "court_ruling", label: "פסקי דין" },
+ { value: "appeals_committee", label: "ועדת ערר" },
+];
+
function isTagged(it: GoldsetItem): boolean {
// Fully tagged only when ALL THREE answers are set — otherwise, in
// "hide tagged" mode, a card would vanish the moment is_holding is clicked,
@@ -201,6 +212,12 @@ function TagCard({
>
{cleanCitation(it.case_number)}
+
+ {sourceLabel(it.source_type)}
+
מכונה: {it.rule_type}
{it.confidence != null && (
ביטחון {it.confidence.toFixed(2)}
@@ -282,13 +299,24 @@ export function GoldsetPanel() {
const createSample = useCreateGoldsetSample(batch);
const [focusedId, setFocusedId] = useState
(null);
const [hideTagged, setHideTagged] = useState(false);
+ const [sourceFilter, setSourceFilter] =
+ useState<"all" | "court_ruling" | "appeals_committee">("all");
const items = useMemo(() => data?.items ?? [], [data]);
const taggedCount = items.filter(isTagged).length;
- const visible = useMemo(
- () => (hideTagged ? items.filter((i) => !isTagged(i)) : items),
- [items, hideTagged],
- );
+ const sourceCounts = useMemo(() => ({
+ court_ruling: items.filter((i) => i.source_type === "court_ruling").length,
+ appeals_committee: items.filter((i) => i.source_type === "appeals_committee").length,
+ }), [items]);
+ const visible = useMemo(() => {
+ let v = items;
+ if (sourceFilter !== "all") v = v.filter((i) => i.source_type === sourceFilter);
+ if (hideTagged) v = v.filter((i) => !isTagged(i));
+ // group-sort: כל פסקי-הדין יחד, ואז כל החלטות ועדת-הערר (הפרדה ברורה).
+ const order = (s: string | null) =>
+ s === "court_ruling" ? 0 : s === "appeals_committee" ? 1 : 2;
+ return [...v].sort((a, b) => order(a.source_type) - order(b.source_type));
+ }, [items, hideTagged, sourceFilter]);
const focused = focusedId ? visible.find((i) => i.id === focusedId) ?? null : null;
@@ -363,6 +391,20 @@ export function GoldsetPanel() {
+ {/* source separation — פסקי-דין מול החלטות ועדת-ערר */}
+
+ {SOURCE_FILTERS.map((s) => (
+
+ ))}
+
+
{taggedCount}/{items.length} תויגו
diff --git a/web-ui/src/lib/api/goldset.ts b/web-ui/src/lib/api/goldset.ts
index 7e389ad..060b03c 100644
--- a/web-ui/src/lib/api/goldset.ts
+++ b/web-ui/src/lib/api/goldset.ts
@@ -28,6 +28,7 @@ export type GoldsetItem = {
review_status: string;
case_number: string | null;
case_name: string | null;
+ source_type: string | null; // 'court_ruling' | 'appeals_committee' | ''
};
export type GoldsetScore = {