feat(cases): תצוגת "פסיקה שצוטטה בהחלטה" בעמוד-התיק + שחזור חיווט-הרמס
UI שביקש חיים: בכניסה להחלטה רואים את הפסיקה שצוטטה בתוכה — מקושרת לספרייה
(קליק → /precedents/[id]) מול חסרה (סומנה אוטומטית להעלאה).
- web/app.py: GET /api/cases/{case}/citations — מהשורה internal_committee של
ההחלטה ב-case_law → precedent_internal_citations: linked (join case_law) +
missing (unresolved + האם flagged ב-missing_precedents).
- web-ui: lib/api/citations.ts (hook) + CitationsSection ב-drafts-panel
(מוצג כשההחלטה בספרייה). מקושרת=ירוק/קליק, חסרה=ענבר "סומנה להעלאה".
- scripts/curator_apply_pipeline_branch.py: מקור-אמת לחיווט-הכפתורים של הרמס
(ה-prompt חי רק ב-Paperclip DB). מקדים branch שמריץ את pipeline-ה-final
ל-wake reason final_learning_*/final_halacha_* (HOME/DOTENV/DATA_DIR מוחלטים
→ מפתחות DeepSeek+Gemini + DATA_DIR נפתרים נכון). idempotent, שני הסוכנים.
כבר הוחל ב-DB; הסקריפט לשחזור אחרי reset.
אומת: py_compile ✓ · tsc ✓ · החיווט אומת חי על 8126 (deepseek+gemini, dedup,
✓ pipeline הושלם). G2 (יכולת חסרה) · INV-LRN1/G10 נשמרים.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
59
web/app.py
59
web/app.py
@@ -3222,6 +3222,65 @@ async def api_get_active_draft(case_number: str):
|
||||
}
|
||||
|
||||
|
||||
@app.get("/api/cases/{case_number}/citations")
|
||||
async def api_case_citations(case_number: str):
|
||||
"""Precedents CITED inside this case's signed decision — split into those linked to
|
||||
the precedent library and those still missing from it (flagged for upload).
|
||||
|
||||
Powers the case-page "פסיקה שצוטטה בהחלטה" panel. Source: the decision's row in
|
||||
case_law (source_kind='internal_committee') → precedent_internal_citations."""
|
||||
case = await db.get_case_by_number(case_number)
|
||||
if not case:
|
||||
raise HTTPException(404, f"תיק {case_number} לא נמצא")
|
||||
pool = await db.get_pool()
|
||||
async with pool.acquire() as conn:
|
||||
law_id = await conn.fetchval(
|
||||
"SELECT id FROM case_law WHERE case_number = $1 "
|
||||
"AND source_kind = 'internal_committee' ORDER BY created_at DESC LIMIT 1",
|
||||
case_number,
|
||||
)
|
||||
if not law_id:
|
||||
# decision not yet in the library (e.g. final not uploaded)
|
||||
return {"in_library": False, "linked": [], "missing": []}
|
||||
linked = await conn.fetch(
|
||||
"SELECT pic.cited_case_number, cl.id AS cited_id, cl.case_name, cl.court, "
|
||||
" cl.precedent_level "
|
||||
"FROM precedent_internal_citations pic "
|
||||
"JOIN case_law cl ON cl.id = pic.cited_case_law_id "
|
||||
"WHERE pic.source_case_law_id = $1 "
|
||||
"ORDER BY pic.cited_case_number",
|
||||
law_id,
|
||||
)
|
||||
missing = await conn.fetch(
|
||||
"SELECT DISTINCT pic.cited_case_number, "
|
||||
" EXISTS(SELECT 1 FROM missing_precedents mp "
|
||||
" WHERE mp.citation = pic.cited_case_number AND mp.status = 'open') AS flagged "
|
||||
"FROM precedent_internal_citations pic "
|
||||
"WHERE pic.source_case_law_id = $1 AND pic.cited_case_law_id IS NULL "
|
||||
" AND pic.cited_case_number <> '' "
|
||||
"ORDER BY pic.cited_case_number",
|
||||
law_id,
|
||||
)
|
||||
return {
|
||||
"in_library": True,
|
||||
"case_law_id": str(law_id),
|
||||
"linked": [
|
||||
{
|
||||
"citation": r["cited_case_number"],
|
||||
"cited_id": str(r["cited_id"]),
|
||||
"case_name": r["case_name"] or "",
|
||||
"court": r["court"] or "",
|
||||
"precedent_level": r["precedent_level"] or "",
|
||||
}
|
||||
for r in linked
|
||||
],
|
||||
"missing": [
|
||||
{"citation": r["cited_case_number"], "flagged": r["flagged"]}
|
||||
for r in missing
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
@app.post("/api/cases/{case_number}/exports/{filename}/mark-final")
|
||||
async def api_mark_final(case_number: str, filename: str):
|
||||
"""Mark an export as the final version — copies to training corpus."""
|
||||
|
||||
Reference in New Issue
Block a user