feat: תיקון-ציטוט בדלי-החילוץ + קישור-לתור מדף-פרט (#133 follow-ups)
All checks were successful
G12 Leak-Guard / leak-guard (pull_request) Successful in 6s

אושר ב-Claude Design (כרטיס 20-halacha-followups).

א׳ תיקון-חילוץ אמיתי ל-quote_unverified:
- `update_halacha` מקבל `supporting_quote`; בעדכונו מריץ `_verify_quote`
  הקיים מול `case_law.full_text` השמור (דטרמיניסטי — בלי OCR/LLM מחדש,
  feedback_no_reocr_retrofit) ומסנכרן `quote_verified` + מוסיף/מסיר את
  הדגל `quote_unverified`. יו"ר שמדביק את הנוסח הנכון מהמקור → הדגל נמחק
  → ההלכה עוזבת את דלי-החילוץ. `HalachaUpdateRequest`+handler מעבירים את
  השדה; `HalachaPatch` + מצב-העריכה ב-HalachaCard כוללים textarea-ציטוט
  (נשלח רק כששונה) + hint.

ב׳ דף-פרט פסיקה — ביטול כפילות-המשטח:
- הלכה pending ב-`ExtractedHalachotSection` מציגה קישור "עבור לתור הלכות"
  במקום כפתורי אשר/דחה כפולים (שער-אישור יחיד, INV-IA/G10).
- `/precedents` Tabs הפך נשלט וקורא `?tab=review` (post-mount, בלי
  hydration-mismatch) כדי שהקישור ינחת על טאב-התור.

display-only ל-G10 (האימות מסנכרן מטא-איכות, לא review_status). ולידציה:
py_compile + tsc + eslint נקיים.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-12 09:03:29 +00:00
parent 99fe16a43d
commit 2962538c09
6 changed files with 96 additions and 25 deletions

View File

@@ -42,7 +42,11 @@ function cleanCitation(s: string | null | undefined): string {
return s.replace(/[--]/g, "").trim();
}
type EditState = { rule_statement: string; reasoning_summary: string };
type EditState = {
rule_statement: string;
reasoning_summary: string;
supporting_quote: string; // #133 — editing this re-verifies vs the source
};
// ─── Panel deliberation (#133/FU-2) ───────────────────────────────────────────
// Surfaces the 3-judge panel's vote+rationale inside the chair's review card so
@@ -143,6 +147,7 @@ function HalachaCard({
const [draft, setDraft] = useState<EditState>({
rule_statement: h.rule_statement,
reasoning_summary: h.reasoning_summary,
supporting_quote: h.supporting_quote,
});
useEffect(() => {
@@ -150,11 +155,21 @@ function HalachaCard({
setDraft({
rule_statement: h.rule_statement,
reasoning_summary: h.reasoning_summary,
supporting_quote: h.supporting_quote,
});
}, [h.id, h.rule_statement, h.reasoning_summary]);
}, [h.id, h.rule_statement, h.reasoning_summary, h.supporting_quote]);
const onSubmitEdit = async () => {
await onSave(draft);
// Only send the quote when it actually changed — that triggers server-side
// re-verification + flag sync (#133); unchanged edits keep the old behavior.
const patch: Partial<EditState> = {
rule_statement: draft.rule_statement,
reasoning_summary: draft.reasoning_summary,
};
if (draft.supporting_quote !== h.supporting_quote) {
patch.supporting_quote = draft.supporting_quote;
}
await onSave(patch);
setEditing(false);
};
@@ -232,9 +247,22 @@ function HalachaCard({
</div>
<div>
<div className="text-[0.7rem] text-ink-muted mb-1">ציטוט תומך</div>
<blockquote className="text-ink-soft text-sm leading-relaxed border-r-2 border-gold pr-3" dir="rtl">
&ldquo;{h.supporting_quote}&rdquo;
</blockquote>
{editing ? (
<>
<Textarea
value={draft.supporting_quote} rows={4} dir="rtl"
onChange={(e) => setDraft({ ...draft, supporting_quote: e.target.value })}
className="bg-gold-wash/50 border-gold/30"
/>
<p className="text-[0.66rem] text-info mt-1 leading-snug">
השמירה מאמתת את הציטוט מול טקסט-המקור; אם תואם הדגל ״ציטוט לא-מאומת״ יוסר.
</p>
</>
) : (
<blockquote className="text-ink-soft text-sm leading-relaxed border-r-2 border-gold pr-3" dir="rtl">
&ldquo;{h.supporting_quote}&rdquo;
</blockquote>
)}
</div>
</div>