feat(learning): grow style-exemplars from every final (P1 #5)
The style-exemplar corpus (channel B — the writer's block-level retrieval of Dafna's real prose) was FROZEN at the one-time seed backfill: new finals were enrolled into style_corpus but never broken into exemplars, so the richest style channel never grew (8137/8126/8174 had 0 exemplars). The writer kept retrieving only March–April seed paragraphs no matter how many finals were signed. Extract the per-decision exemplar logic (section→paragraph→Voyage-embed→replace) into a shared service `legal_mcp.services.style_exemplars.extract_and_store` — the SINGLE implementation now used by BOTH the one-time backfill and the live enrollment path (G2; no parallel extractor). `_enroll_final_in_library` calls it on every final upload (source='internal_committee', the same source the writer's search_style_exemplars reads). Voyage embeds over REST → container-safe; best-effort, surfaced in the upload response, never fails the upload. Effect: every signed final now grows the exemplar corpus, so the writer's block-level style retrieval improves with each decision — the core "learn from every decision" fix for channel B. Path A (style_distance_history) will track whether the larger exemplar pool reduces style-distance over time. Invariants: G2 (one extraction path shared by backfill + enroll), INV-LRN5 (style/structure prose only — substance routes elsewhere), INV-LRN4 (the draft↔final loop now feeds the exemplar channel, not just the lesson channel). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
16
web/app.py
16
web/app.py
@@ -3769,6 +3769,22 @@ async def _enroll_final_in_library(
|
||||
logger.warning("inline metadata extraction failed for %s: %s", case_number, e)
|
||||
out["metadata_error"] = str(e)
|
||||
|
||||
# Grow the style-exemplar corpus (channel B): break this final into block-level
|
||||
# paragraphs the writer retrieves (07-learning §0.2). Before this, exemplars were
|
||||
# frozen at the one-time seed backfill — new finals never got exemplarized, so the
|
||||
# richest style channel never grew. Same extraction the backfill uses (G2). Voyage
|
||||
# embeds over REST → container-safe. Best-effort; surfaced, never fails the upload.
|
||||
try:
|
||||
from legal_mcp.services import style_exemplars as _sx
|
||||
n_ex = await _sx.extract_and_store(
|
||||
decision_number=case_number, source="internal_committee",
|
||||
full_text=final_text, practice_area=case.get("practice_area", ""),
|
||||
)
|
||||
out["exemplars"] = n_ex
|
||||
except Exception as e:
|
||||
logger.warning("style-exemplar extraction failed for %s: %s", case_number, e)
|
||||
out["exemplars_error"] = str(e)
|
||||
|
||||
# The precedents this decision cites → link to the library; flag the ones not found.
|
||||
try:
|
||||
await cit_tools.extract_internal_citations(case_law_id=case_law_id, limit=0)
|
||||
|
||||
Reference in New Issue
Block a user