feat(principles): canonical_statement synthesis service + throttled backfill (Phase E groundwork, #152)
Grounded (INV-AH) multi-instance synthesis with drift guard + chair gate (pending_review, G10). Single path used by backfill, MCP tool, nightly drain. HELD from production run pending the principles-redesign (rename+cull, #152). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -21,7 +21,7 @@ from __future__ import annotations
|
||||
import time
|
||||
from uuid import UUID
|
||||
|
||||
from legal_mcp.services import db, precedent_library, telemetry
|
||||
from legal_mcp.services import canonical_synthesis, db, precedent_library, telemetry
|
||||
from legal_mcp.tools.envelope import empty, err as _err, ok as _ok # GAP-48: SSoT envelope
|
||||
|
||||
|
||||
@@ -439,3 +439,34 @@ async def canonical_halacha_get(canonical_id: str) -> str:
|
||||
if row is None:
|
||||
return _err("עיקרון קנוני לא נמצא")
|
||||
return _ok(row)
|
||||
|
||||
|
||||
async def canonical_synthesize_pending(limit: int = 20) -> str:
|
||||
"""סנתז ניסוח-קנוני לעקרונות הממתינים (review_status='pending_synthesis'). V41 Phase 4.
|
||||
|
||||
לכל עיקרון: מודל מקומי (claude_session) מזקק ניסוח אחד, כללי ומעוגן בציטוטי-המופעים
|
||||
(INV-AH), שער-drift דוחה סטייה גדולה מדי, והסטטוס מתקדם ל-pending_review לשער-היו"ר
|
||||
(G10). on-demand / burst ידני; המסה הראשונית מטופלת ב-backfill_canonical_synthesis.py.
|
||||
|
||||
Args:
|
||||
limit: מספר מקסימלי לסבב (עד 100). רב-instance מטופלים ראשונים.
|
||||
"""
|
||||
pool = await db.get_pool()
|
||||
rows = await pool.fetch(
|
||||
"SELECT id::text AS id FROM canonical_halachot "
|
||||
"WHERE review_status='pending_synthesis' "
|
||||
"ORDER BY instance_count DESC, created_at LIMIT $1",
|
||||
min(max(limit, 1), 100),
|
||||
)
|
||||
if not rows:
|
||||
return _ok({"processed": 0, "results": [], "message": "אין עקרונות ממתינים לסינתזה"})
|
||||
results = []
|
||||
counts: dict[str, int] = {}
|
||||
for r in rows:
|
||||
res = await canonical_synthesis.synthesize_and_apply(UUID(r["id"]))
|
||||
counts[res["status"]] = counts.get(res["status"], 0) + 1
|
||||
results.append({
|
||||
"canonical_id": res["canonical_id"], "status": res["status"],
|
||||
"drift_cosine": res.get("drift_cosine"), "reason": res.get("reason", ""),
|
||||
})
|
||||
return _ok({"processed": len(results), "by_status": counts, "results": results})
|
||||
|
||||
Reference in New Issue
Block a user