feat: Stage A finalizers + #35/#36/#37 — critical-gap closure
Some checks failed
Build & Deploy / build-and-deploy (push) Has been cancelled
Some checks failed
Build & Deploy / build-and-deploy (push) Has been cancelled
Four parallel sub-agents closed the remaining critical gaps from the 26/05 Stage A/B sprint. Each block independently tested; aggregated here. ## #30/#31 finalizers (sub-agent A) * Auto-derive practice_area in case_create from case_number prefix (1xxx→rishuy_uvniya, 8xxx→betterment_levy, 9xxx→compensation_197); default for CaseCreateRequest is now "" (the DB constraint catches any stray "appeals_committee"). * practice_area.py: derive_subtype now handles axis-B domain values (rishuy_uvniya/betterment_levy/compensation_197) without parsing the case number; new helper derive_domain_practice_area(). * Halacha re-extraction verified unnecessary — all 6 reclassified records already had is_binding=false and approved halachot. * Regression tests: 6 cases in tests/test_corpus_constraints.py covering practice_area enum, internal-committee chair/district, external-upload arar prefix, MCP guard. * UI: district input → Select dropdown (7 districts) in precedent-edit-sheet.tsx, preserving legacy free-text values. ## #37 בל"מ subtypes (sub-agent B) * 3 new appeal_subtypes: extension_request_{building_permit, betterment_levy,compensation}. APPEALS_COMMITTEE_SUBTYPES extended, SUBTYPES_BY_AREA mappings added. * New helpers: is_blam_subject(), is_blam_subtype(), derive_subtype_with_blam(case_number, subject, practice_area). case_create now uses it to auto-detect "בקשה להארכת מועד" subjects. * 3 methodology templates under docs/methodology/extension-request-*.md. * paperclip_client.py mapping updated for the 3 new subtypes (extension_request_building_permit→CMP, the other two→CMPA). * Frontend: bilingual "בל"מ" badge + filter dropdown on cases list + detail header; appeal-type-bars collapseBlam() merges בל"מ into its parent domain for aggregate bars. * Wizard auto-detects בל"מ from subject during case creation. * 3 Berlinger cases (1017/1018/1019-03-26) migrated to appeal_subtype=extension_request_building_permit via psql. ## #35 missing_precedents feature (sub-agent C) * Schema V13: missing_precedents table (citation, case_id, party, legal_topic, status, linked_case_law_id, claim_quote, ...) + FK constraints + 3 indexes. Applied via psql + idempotent migration. * 6 db.py service functions, 3 MCP tools, 6 FastAPI endpoints (POST/GET/PATCH/DELETE/upload — upload routes by citation prefix to ingest_internal_decision or ingest_precedent). * Next.js page /missing-precedents with 5 status tabs + filters + sidebar badge counter + detail drawer with metadata edit + smart upload form that switches fields per committee/court. * Bootstrap: 7 rows imported from the JSON file (3 citations × cases, all status=closed with linked_case_law_id). * legal-researcher.md: new §2ב.5 with missing_precedent_create usage + dedup semantics + tool grant. ## #36 legal_arguments aggregation (sub-agent D) * Schema V14: legal_arguments + legal_argument_propositions M:M. Applied via psql. * New service argument_aggregator.py with two functions — aggregate_claims_to_arguments() (Claude CLI / claude_session) and get_legal_arguments(). Graceful llm_unavailable handling when CLI is missing (containers). * 2 MCP tools + 2 API endpoints (POST .../aggregate-arguments as BackgroundTask, GET .../legal-arguments). * Frontend: shadcn Accordion + new legal-arguments-panel.tsx with hierarchical (party → priority badge → arguments) display, "טיעונים" tab on the case page, "חשב/חשב מחדש" buttons. * scripts/backfill_legal_arguments.py + SCRIPTS.md entry — dry-run found 8 candidate cases including 1017/1018/1019. ## Open follow-ups (intentionally deferred) * npm run api:types in web-ui (CLAUDE.md flow) — recommended before the next UI commit; not required for backend deployment. * Run backfill_legal_arguments.py --apply once the container picks up the new aggregator service. * webhook on missing-precedents upload-close to Paperclip (optional). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -54,6 +54,8 @@ from legal_mcp.tools import ( # noqa: E402
|
||||
cases, documents, search, drafting, workflow, precedents,
|
||||
precedent_library as plib,
|
||||
internal_decisions as int_tools,
|
||||
legal_arguments as la_tools,
|
||||
missing_precedents as mp_tools,
|
||||
)
|
||||
|
||||
|
||||
@@ -364,6 +366,28 @@ async def get_claims(
|
||||
return await documents.get_claims(case_number, party_role)
|
||||
|
||||
|
||||
# Legal arguments — aggregated (de-duped) propositions
|
||||
@mcp.tool()
|
||||
async def aggregate_claims_to_arguments(
|
||||
case_number: str,
|
||||
force: bool = False,
|
||||
) -> str:
|
||||
"""כינוס פרופוזיציות גולמיות (claims) לטיעונים משפטיים מובחנים — ~6-12 לכל צד.
|
||||
|
||||
משתמש ב-Claude headless לסיווג ואיגוד. force=True מוחק טיעונים קיימים לפני חישוב מחדש.
|
||||
"""
|
||||
return await la_tools.aggregate_claims_to_arguments(case_number, force=force)
|
||||
|
||||
|
||||
@mcp.tool()
|
||||
async def get_legal_arguments(
|
||||
case_number: str,
|
||||
party: str = "",
|
||||
) -> str:
|
||||
"""שליפת טיעונים משפטיים מאוגדים. party: appellant/respondent/committee/permit_applicant (ריק=הכל)."""
|
||||
return await la_tools.get_legal_arguments(case_number, party)
|
||||
|
||||
|
||||
# References
|
||||
@mcp.tool()
|
||||
async def extract_references(
|
||||
@@ -703,6 +727,82 @@ async def internal_decision_upload(
|
||||
)
|
||||
|
||||
|
||||
# ── Missing precedents (TaskMaster #35) ───────────────────────────
|
||||
|
||||
|
||||
@mcp.tool()
|
||||
async def missing_precedent_create(
|
||||
citation: str,
|
||||
case_number: str = "",
|
||||
cited_in_document_id: str = "",
|
||||
cited_by_party: str = "unknown",
|
||||
cited_by_party_name: str = "",
|
||||
legal_topic: str = "",
|
||||
legal_issue: str = "",
|
||||
claim_quote: str = "",
|
||||
case_name: str = "",
|
||||
notes: str = "",
|
||||
) -> str:
|
||||
"""תיעוד פסיקה שצוטטה בכתבי הטענות אך אינה בקורפוס.
|
||||
|
||||
שימוש: סוכן המחקר (legal-researcher) קורא לזה כשהוא מזהה ציטוט שלא
|
||||
ניתן לאמת מול הקורפוס. הרשומה נשארת 'open' עד שהיו"ר מעלה את הפסיקה.
|
||||
cited_by_party: appellant / respondent / committee / permit_applicant / unknown.
|
||||
דה-דופ אוטומטי: ציטוט+תיק זהים → מחזיר את הרשומה הקיימת.
|
||||
"""
|
||||
return await mp_tools.missing_precedent_create(
|
||||
citation=citation,
|
||||
case_number=case_number,
|
||||
cited_in_document_id=cited_in_document_id,
|
||||
cited_by_party=cited_by_party,
|
||||
cited_by_party_name=cited_by_party_name,
|
||||
legal_topic=legal_topic,
|
||||
legal_issue=legal_issue,
|
||||
claim_quote=claim_quote,
|
||||
case_name=case_name,
|
||||
notes=notes,
|
||||
)
|
||||
|
||||
|
||||
@mcp.tool()
|
||||
async def missing_precedent_list(
|
||||
case_number: str = "",
|
||||
status: str = "open",
|
||||
legal_topic: str = "",
|
||||
limit: int = 50,
|
||||
) -> str:
|
||||
"""רשימת פסיקות חסרות לתיק או בכלל. status: open/uploaded/closed/irrelevant.
|
||||
|
||||
שימוש: היו"ר רואה מה ממתין להעלאה; הסוכן מאשר שלא יוצר כפילויות.
|
||||
"""
|
||||
return await mp_tools.missing_precedent_list(
|
||||
case_number=case_number,
|
||||
status=status,
|
||||
legal_topic=legal_topic,
|
||||
limit=limit,
|
||||
)
|
||||
|
||||
|
||||
@mcp.tool()
|
||||
async def missing_precedent_close(
|
||||
id: str,
|
||||
linked_case_law_id: str = "",
|
||||
notes: str = "",
|
||||
status: str = "closed",
|
||||
) -> str:
|
||||
"""סגירת רשומת פסיקה חסרה לאחר העלאה לקורפוס.
|
||||
|
||||
status: closed (הועלה ונקשר) / uploaded (הועלה, ממתין לקישור) /
|
||||
irrelevant (היו"ר החליט שזה לא רלוונטי לקורפוס).
|
||||
"""
|
||||
return await mp_tools.missing_precedent_close(
|
||||
id=id,
|
||||
linked_case_law_id=linked_case_law_id,
|
||||
notes=notes,
|
||||
status=status,
|
||||
)
|
||||
|
||||
|
||||
@mcp.tool()
|
||||
async def record_chair_feedback(
|
||||
case_number: str,
|
||||
|
||||
Reference in New Issue
Block a user