Legal-i Claude Opus 4.7 (1M context) commited on
Commit
76b9874
·
1 Parent(s): 336fd72

feat(Day 49 phase 1.5): GET /v1/doctrines/{id} for dossier expand

Browse files

Adds per-doctrine details endpoint for the dossier click-to-expand
UX. Returns name_he, elements, exceptions, statute_refs (full),
leading_cases (full), and pending_review flag. Keywords stay
internal — they're a tuning surface, not user-facing.

CRITICAL: registered AFTER /v1/doctrines/catalog so the static
path matches first. FastAPI routes match in registration order,
so /v1/doctrines/{doctrine_id} placed earlier would shadow catalog.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

Files changed (1) hide show
  1. tau_rag/api/fastapi_app.py +38 -0
tau_rag/api/fastapi_app.py CHANGED
@@ -22620,3 +22620,41 @@ def doctrines_catalog_public(): # type: ignore
22620
  return JSONResponse(status_code=500, content={
22621
  "ok": False, "error": f"{type(e).__name__}: {e}"
22622
  })
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
22620
  return JSONResponse(status_code=500, content={
22621
  "ok": False, "error": f"{type(e).__name__}: {e}"
22622
  })
22623
+
22624
+
22625
+ @app.get("/v1/doctrines/{doctrine_id}")
22626
+ def doctrines_get_one(doctrine_id: str): # type: ignore
22627
+ """Day 49 — full per-doctrine details for the dossier expand-on-click.
22628
+
22629
+ Returns name_he, elements, exceptions, statute_refs, all leading_cases,
22630
+ and the `pending_lawyer_review` flag. Keywords stay internal —
22631
+ they're a tuning surface, not user-facing.
22632
+
22633
+ NOTE: must be registered AFTER /v1/doctrines/catalog so the
22634
+ static path wins over the dynamic match.
22635
+ """
22636
+ try:
22637
+ from ..intelligence.doctrine_classifier import load_doctrine_catalog
22638
+ cat = load_doctrine_catalog()
22639
+ idx = {d["id"]: d for d in cat.get("doctrines", [])}
22640
+ doc = idx.get(doctrine_id)
22641
+ if not doc:
22642
+ return JSONResponse(status_code=404, content={
22643
+ "ok": False, "reason": "doctrine_not_found",
22644
+ })
22645
+ return {
22646
+ "ok": True,
22647
+ "id": doc.get("id"),
22648
+ "name_he": doc.get("name_he"),
22649
+ "name_en": doc.get("name_en"),
22650
+ "domain": doc.get("domain"),
22651
+ "elements": doc.get("elements") or [],
22652
+ "exceptions": doc.get("exceptions") or [],
22653
+ "statute_refs": doc.get("statute_refs") or [],
22654
+ "leading_cases": doc.get("leading_cases") or [],
22655
+ "pending_review": bool(doc.get("_pending_lawyer_review")),
22656
+ }
22657
+ except Exception as e:
22658
+ return JSONResponse(status_code=500, content={
22659
+ "ok": False, "error": f"{type(e).__name__}: {e}"
22660
+ })