Merge pull request 'feat(graph): in-app corpus citation graph (/graph) — Phase 1' (#113) from worktree-corpus-graph into main
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 3m44s

This commit was merged in pull request #113.
This commit is contained in:
2026-06-07 18:52:01 +00:00
11 changed files with 1651 additions and 0 deletions

View File

@@ -5757,6 +5757,48 @@ async def precedent_remove_relation(case_law_id: str, related_id: str):
return {"unlinked": True, "case_law_id": case_law_id, "related_id": related_id}
# ── Corpus graph (the /graph page) ────────────────────────────────────
# Read-only topology projection of the precedent corpus — nodes + edges
# assembled live from the canonical tables (G2: no parallel store, no drift).
# NOT a retrieval path (03-retrieval): returns graph structure, not ranked
# search results. Explicit Pydantic response_model (graph_api.CorpusGraph) so
# the OpenAPI schema emits real types for the UI (UI2).
from web import graph_api # noqa: E402 (FastAPI-only, web-ui-facing read projection)
@app.get("/api/graph/corpus", response_model=graph_api.CorpusGraph)
async def graph_corpus(
practice_area: str = "",
source: str = "",
node_types: str = "",
min_citations: int = 0,
limit: int = graph_api.NODE_CAP_DEFAULT,
q: str = "",
):
"""Full corpus graph under the given filters (most-cited nodes survive the cap)."""
if practice_area and practice_area not in _PRACTICE_AREAS:
raise HTTPException(400, "practice_area לא תקין")
pool = await db.get_pool()
return await graph_api.build_corpus_graph(
pool,
practice_area=practice_area,
source=source,
node_types=node_types,
min_citations=min_citations,
limit=limit,
q=q,
)
@app.get("/api/graph/node/{node_id}/neighborhood", response_model=graph_api.CorpusGraph)
async def graph_node_neighborhood(node_id: str, depth: int = 1, node_types: str = ""):
"""Local-graph focus: the node + its neighbors out to ``depth`` (1-2)."""
pool = await db.get_pool()
return await graph_api.build_node_neighborhood(
pool, node_id, depth=depth, node_types=node_types
)
# Halacha and metadata extraction are LLM-driven and rely on the local
# `claude` CLI via mcp-server/services/claude_session.py — they CANNOT run
# from this container (no CLI, no claude.ai session). The endpoints below