feat(halachot): Phase 5 — canonical panel UI + instances accordion (V41)
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:
@@ -5494,12 +5494,15 @@ async def list_halachot(
|
||||
h.cites, h.confidence, h.quote_verified, h.quality_flags,
|
||||
h.review_status,
|
||||
h.reviewer, h.reviewed_at, h.created_at, h.updated_at,
|
||||
h.canonical_id, h.instance_type,
|
||||
ch.canonical_statement, ch.instance_count,
|
||||
cl.case_number, cl.case_name, cl.court, cl.date AS decision_date,
|
||||
cl.precedent_level,
|
||||
COALESCE(cor.corroboration_count, 0)::int AS corroboration_count,
|
||||
COALESCE(cor.corroboration_negative, false) AS corroboration_negative,
|
||||
pr.verdict AS panel_verdict
|
||||
FROM halachot h
|
||||
LEFT JOIN canonical_halachot ch ON ch.id = h.canonical_id
|
||||
LEFT JOIN case_law cl ON cl.id = h.case_law_id
|
||||
LEFT JOIN (
|
||||
SELECT halacha_id,
|
||||
@@ -6144,6 +6147,21 @@ async def update_canonical_statement(
|
||||
return result.split()[-1] != "0"
|
||||
|
||||
|
||||
async def list_canonical_instances(canonical_id: "UUID") -> list[dict]:
|
||||
"""List all halachot (instances) sharing a canonical_id — used by the UI accordion."""
|
||||
pool = await get_pool()
|
||||
rows = await pool.fetch(
|
||||
"""SELECT h.id, h.instance_type, h.confidence, h.rule_statement,
|
||||
cl.case_number, cl.case_name
|
||||
FROM halachot h
|
||||
LEFT JOIN case_law cl ON cl.id = h.case_law_id
|
||||
WHERE h.canonical_id = $1
|
||||
ORDER BY h.instance_type, cl.case_number""",
|
||||
canonical_id,
|
||||
)
|
||||
return [dict(r) for r in rows]
|
||||
|
||||
|
||||
async def _annotate_equivalents(pool, out: list[dict]) -> None:
|
||||
"""Attach an `equivalents` list to each row (#84.2) — parallel-authority links.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user