Add content checklists for block-yod and chair feedback system
Addresses Dafna's observation that licensing decisions lack comprehensive planning discussion. Systematic corpus analysis of all 24 training decisions revealed the system learned writing style but not substantive content. Changes: - Corpus analysis of all 24 decisions (docs/corpus-analysis.md) - 5 content checklists by appeal subtype injected into block-yod prompt - chair_feedback DB table + API endpoints + MCP tools - Feedback management page in Next.js UI (/feedback) - Navigation updated with "הערות יו״ר" link Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
127
web/app.py
127
web/app.py
@@ -2302,6 +2302,133 @@ async def api_reprocess_document(case_number: str, doc_id: str):
|
||||
return {"status": "reprocessing"}
|
||||
|
||||
|
||||
# ── Chair feedback endpoints ──────────────────────────────────────
|
||||
|
||||
|
||||
@app.get("/api/feedback")
|
||||
async def api_list_feedback(
|
||||
case_number: str = "",
|
||||
category: str = "",
|
||||
unresolved_only: bool = False,
|
||||
):
|
||||
"""List chair feedback, optionally filtered by case/category."""
|
||||
case_id = None
|
||||
if case_number:
|
||||
case = await db.get_case_by_number(case_number)
|
||||
if case:
|
||||
case_id = UUID(case["id"])
|
||||
|
||||
feedbacks = await db.list_chair_feedback(
|
||||
case_id=case_id,
|
||||
category=category or None,
|
||||
unresolved_only=unresolved_only,
|
||||
)
|
||||
|
||||
items = []
|
||||
# Build case_number lookup
|
||||
case_numbers: dict[str, str] = {}
|
||||
pool = await db.get_pool()
|
||||
for fb in feedbacks:
|
||||
cid = fb.get("case_id")
|
||||
cn = ""
|
||||
if cid and str(cid) not in case_numbers:
|
||||
async with pool.acquire() as conn:
|
||||
row = await conn.fetchrow(
|
||||
"SELECT case_number, title FROM cases WHERE id = $1", cid,
|
||||
)
|
||||
if row:
|
||||
case_numbers[str(cid)] = row["case_number"]
|
||||
if cid:
|
||||
cn = case_numbers.get(str(cid), "")
|
||||
|
||||
items.append({
|
||||
"id": str(fb["id"]),
|
||||
"case_id": str(fb["case_id"]) if fb["case_id"] else None,
|
||||
"case_number": cn,
|
||||
"block_id": fb["block_id"],
|
||||
"category": fb["category"],
|
||||
"feedback_text": fb["feedback_text"],
|
||||
"lesson_extracted": fb["lesson_extracted"],
|
||||
"resolved": fb["resolved"],
|
||||
"applied_to": fb.get("applied_to", []),
|
||||
"created_at": fb["created_at"].isoformat() if fb.get("created_at") else None,
|
||||
})
|
||||
|
||||
return items
|
||||
|
||||
|
||||
@app.post("/api/feedback")
|
||||
async def api_create_feedback(
|
||||
case_number: str = Form(""),
|
||||
block_id: str = Form("block-yod"),
|
||||
feedback_text: str = Form(...),
|
||||
category: str = Form("missing_content"),
|
||||
lesson_extracted: str = Form(""),
|
||||
):
|
||||
"""Record a new chair feedback entry."""
|
||||
case_id = None
|
||||
if case_number:
|
||||
case = await db.get_case_by_number(case_number)
|
||||
if case:
|
||||
case_id = UUID(case["id"])
|
||||
|
||||
valid_categories = [
|
||||
"missing_content", "wrong_tone", "wrong_structure",
|
||||
"factual_error", "style", "other",
|
||||
]
|
||||
if category not in valid_categories:
|
||||
raise HTTPException(400, f"קטגוריה לא חוקית. אפשרויות: {', '.join(valid_categories)}")
|
||||
|
||||
feedback_id = await db.record_chair_feedback(
|
||||
case_id=case_id,
|
||||
block_id=block_id,
|
||||
feedback_text=feedback_text,
|
||||
category=category,
|
||||
lesson_extracted=lesson_extracted,
|
||||
)
|
||||
|
||||
return {"id": str(feedback_id), "status": "created"}
|
||||
|
||||
|
||||
@app.post("/api/feedback/json")
|
||||
async def api_create_feedback_json(body: dict):
|
||||
"""Record a new chair feedback entry (JSON body)."""
|
||||
case_number = body.get("case_number", "")
|
||||
case_id = None
|
||||
if case_number:
|
||||
case = await db.get_case_by_number(case_number)
|
||||
if case:
|
||||
case_id = UUID(case["id"])
|
||||
|
||||
valid_categories = [
|
||||
"missing_content", "wrong_tone", "wrong_structure",
|
||||
"factual_error", "style", "other",
|
||||
]
|
||||
category = body.get("category", "missing_content")
|
||||
if category not in valid_categories:
|
||||
raise HTTPException(400, f"קטגוריה לא חוקית. אפשרויות: {', '.join(valid_categories)}")
|
||||
|
||||
feedback_id = await db.record_chair_feedback(
|
||||
case_id=case_id,
|
||||
block_id=body.get("block_id", "block-yod"),
|
||||
feedback_text=body.get("feedback_text", ""),
|
||||
category=category,
|
||||
lesson_extracted=body.get("lesson_extracted", ""),
|
||||
)
|
||||
|
||||
return {"id": str(feedback_id), "status": "created"}
|
||||
|
||||
|
||||
@app.patch("/api/feedback/{feedback_id}/resolve")
|
||||
async def api_resolve_feedback(feedback_id: str, body: dict):
|
||||
"""Mark feedback as resolved."""
|
||||
await db.resolve_chair_feedback(
|
||||
feedback_id=UUID(feedback_id),
|
||||
applied_to=body.get("applied_to", []),
|
||||
)
|
||||
return {"status": "resolved"}
|
||||
|
||||
|
||||
# ── Background Processing ─────────────────────────────────────────
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user