feat(halachot): Phase 5 — canonical panel UI + instances accordion (V41)
All checks were successful
G12 Leak-Guard / leak-guard (pull_request) Successful in 3s
Lint — undefined names / undefined-names (pull_request) Successful in 10s

UI changes to halacha-review-panel.tsx:
- instance_type badge (עיקרון מקורי / ציטוט / יישום) in meta row
- "מוזכר ב-N פסיקות" pill when instance_count > 1
- CanonicalSection component: canonical_statement (view + edit), instances accordion

Backend:
- list_halachot SQL: adds canonical_id, instance_type, canonical_statement,
  instance_count via LEFT JOIN canonical_halachot
- list_canonical_instances(canonical_id) → compact rows for accordion
- GET /api/canonical-halachot/{canonical_id}/instances endpoint
- PATCH /api/halachot/{id}: canonical_statement propagates to canonical_halachot
- HalachaUpdateRequest: canonical_statement field
- useCanonicalInstances hook + CanonicalInstance type in precedent-library.ts

INV-G10 (chair gate): only the chair can edit canonical_statement (same
flow as rule_statement — PATCH /api/halachot/{id} with reviewer="דפנה").
G2: canonical data flows through canonical_halachot, not a parallel store.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-19 05:41:24 +00:00
parent 75f40cc778
commit dd2e12f902
4 changed files with 218 additions and 1 deletions

View File

@@ -126,6 +126,11 @@ export type Halacha = {
reason: string;
}[];
};
/* V41 — canonical halachot model: one principle, many instances. */
canonical_id?: string | null;
instance_type?: "original" | "citation" | "application" | null;
canonical_statement?: string | null;
instance_count?: number | null;
};
export type RelatedCase = {
@@ -671,8 +676,31 @@ export type HalachaPatch = Partial<{
// #133 — editing the quote re-verifies it against the source server-side and
// clears/sets the quote_unverified flag (extraction repair).
supporting_quote: string;
// V41 — propagated to canonical_halachot.canonical_statement
canonical_statement: string;
}>;
export type CanonicalInstance = {
id: string;
instance_type: "original" | "citation" | "application";
confidence: number;
rule_statement: string;
case_number: string;
case_name: string;
};
export function useCanonicalInstances(canonical_id: string | null | undefined) {
return useQuery({
queryKey: ["canonical-instances", canonical_id],
queryFn: () =>
apiRequest<{ instances: CanonicalInstance[] }>(
`/api/canonical-halachot/${encodeURIComponent(canonical_id!)}/instances`,
).then((r) => r.instances),
enabled: !!canonical_id,
staleTime: 60_000,
});
}
export function useUpdateHalacha() {
const qc = useQueryClient();
return useMutation({