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

@@ -6025,6 +6025,7 @@ class HalachaUpdateRequest(BaseModel):
subject_tags: list[str] | None = None
practice_areas: list[str] | None = None
supporting_quote: str | None = None # #133 — edited quote → re-verify + sync flag
canonical_statement: str | None = None # V41 — updates canonical_halachot.canonical_statement
class HalachaBatchReviewRequest(BaseModel):
@@ -7414,6 +7415,18 @@ async def halacha_equivalents_unlink(halacha_id: str, other_id: str):
return {"ok": await db.unlink_equivalent_halachot(hid, oid)}
# ── Canonical halachot — V41 ─────────────────────────────────────────────────
@app.get("/api/canonical-halachot/{canonical_id}/instances")
async def canonical_halacha_instances(canonical_id: str):
"""All halachot instances sharing a canonical_id (V41 — used by the UI accordion)."""
try:
cid = UUID(canonical_id)
except ValueError:
raise HTTPException(400, "canonical_id לא תקין")
return {"instances": await db.list_canonical_instances(cid)}
# ── Gold-set tagging (#81.7 / #81.8) ─────────────────────────────────────────
class GoldsetSampleRequest(BaseModel):
@@ -7490,6 +7503,16 @@ async def halacha_update(halacha_id: str, req: HalachaUpdateRequest):
)
if not row:
raise HTTPException(404, "הלכה לא נמצאה")
if req.canonical_statement is not None:
# V41: propagate to canonical_halachot; canonical_id not in RETURNING
# so we fetch it separately (one cheap indexed lookup).
_pool = await db.get_pool()
canon_id = await _pool.fetchval(
"SELECT canonical_id FROM halachot WHERE id=$1", hid
)
if canon_id:
from uuid import UUID as _UUID
await db.update_canonical_statement(_UUID(str(canon_id)), req.canonical_statement)
return row