feat(principles): decision-level panel extraction regime — cap-5 + dedup-frees-slot (Phase B, #152)
extract() routes to _extract_via_panel when HALACHA_PANEL_REGIME_ENABLED: the 3-model panel proposes → votes/score → approval rule → dedup vs corpus (known links as citation, frees a cap slot) → cap HALACHA_PANEL_MAX_NEW genuinely-new principles/decision (by score), rest dropped. Replaces single-model auto-approve; legacy path kept as <2-judge fallback. db.store_panel_principles persists the pre-decided verdict + source-aware canonical create/link (G9 reviewer=panel:...). Dry-run validated on 29468-08-23: ~18 → 4 principles. 6 new tests; full suite 422 green. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -5408,6 +5408,82 @@ async def store_halachot_for_chunk(
|
||||
return inserted
|
||||
|
||||
|
||||
async def store_panel_principles(
|
||||
case_law_id: UUID, principles: list[dict],
|
||||
) -> dict:
|
||||
"""Persist principles selected by the tri-model panel regime (#152, Phase B).
|
||||
|
||||
Unlike :func:`store_halachot_for_chunk`, the verdict is ALREADY decided by the
|
||||
panel — this does NOT recompute auto-approve from confidence. Each principle
|
||||
carries its own ``review_status`` (approved / pending_review from the panel),
|
||||
``instance_type`` ('original' = new canonical, 'citation' = link to existing),
|
||||
and ``canonical_id`` (when a citation). The cap-of-5 + dedup-frees-slot is
|
||||
applied by the CALLER (the extractor); this is the atomic writer.
|
||||
|
||||
Provenance (G9): reviewer = "panel:<voters> v<votes>/s<score>". Returns
|
||||
{created_new, linked} counts.
|
||||
"""
|
||||
pool = await get_pool()
|
||||
created_new = linked = 0
|
||||
async with pool.acquire() as conn:
|
||||
async with conn.transaction():
|
||||
base = await conn.fetchval(
|
||||
"SELECT COALESCE(MAX(halacha_index), -1) + 1 FROM halachot "
|
||||
"WHERE case_law_id = $1", case_law_id,
|
||||
)
|
||||
for p in principles:
|
||||
voters = ",".join(p.get("voters") or [])
|
||||
reviewer = f"panel:{voters} v{p.get('votes', 0)}/s{p.get('score', 0)}"
|
||||
approved = p.get("review_status") == "approved"
|
||||
emb = p.get("embedding")
|
||||
canonical_id = p.get("canonical_id")
|
||||
instance_type = p.get("instance_type", "original")
|
||||
idx = base + created_new + linked
|
||||
await conn.execute(
|
||||
"""INSERT INTO halachot
|
||||
(case_law_id, halacha_index, rule_statement, rule_type,
|
||||
reasoning_summary, supporting_quote, page_reference,
|
||||
practice_areas, subject_tags, cites, confidence,
|
||||
quote_verified, quality_flags, embedding, review_status,
|
||||
reviewer, reviewed_at, canonical_id, instance_type)
|
||||
VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,
|
||||
CASE WHEN $17 THEN now() ELSE NULL END,$18,$19)""",
|
||||
case_law_id, idx, p["rule_statement"],
|
||||
p.get("rule_type", "interpretive"), p.get("reasoning_summary", ""),
|
||||
p["supporting_quote"], p.get("page_reference", ""),
|
||||
p.get("practice_areas", []), p.get("subject_tags", []),
|
||||
p.get("cites", []), float(p.get("confidence", p.get("score", 0.0))),
|
||||
p.get("quote_verified", False), p.get("quality_flags", []),
|
||||
emb, p.get("review_status", "pending_review"), reviewer,
|
||||
approved, canonical_id, instance_type,
|
||||
)
|
||||
if instance_type == "citation" and canonical_id is not None:
|
||||
await conn.execute(
|
||||
"UPDATE canonical_halachot SET "
|
||||
"instance_count = instance_count + 1, updated_at = now() "
|
||||
"WHERE id = $1", canonical_id,
|
||||
)
|
||||
linked += 1
|
||||
else:
|
||||
new_canon_id = await conn.fetchval(
|
||||
"INSERT INTO canonical_halachot "
|
||||
"(canonical_statement, rule_type, practice_areas, subject_tags, "
|
||||
" embedding, first_established_in, review_status, instance_count) "
|
||||
"VALUES ($1,$2,$3,$4,$5,$6,'pending_synthesis',1) RETURNING id",
|
||||
p.get("rule_statement") or "", p.get("rule_type", "interpretive"),
|
||||
p.get("practice_areas") or [], p.get("subject_tags") or [],
|
||||
emb, case_law_id,
|
||||
)
|
||||
await conn.execute(
|
||||
"UPDATE halachot SET canonical_id=$1 WHERE case_law_id=$2 "
|
||||
"AND halacha_index=$3", new_canon_id, case_law_id, idx,
|
||||
)
|
||||
created_new += 1
|
||||
logger.info("store_panel_principles: case_law=%s — %d new, %d linked",
|
||||
case_law_id, created_new, linked)
|
||||
return {"created_new": created_new, "linked": linked}
|
||||
|
||||
|
||||
async def list_halachot(
|
||||
case_law_id: UUID | None = None,
|
||||
review_status: str | None = None,
|
||||
|
||||
Reference in New Issue
Block a user