fix(precedents): חילוץ-מטא-דאטה ממלא תחום (practice_area) ושם-יו"ר לכל החלטת-ועדה
שני פערים שצפו מ-/precedents בחילוץ-ההלכות:
1. **practice_area לא סומן** — השדה הועבר ל-LLM כקונטקסט-קריאה-בלבד ולא חולץ
מעולם, כך שהעלאות שהשאירו אותו ריק נשארו ריקות והרדיו ב-/precedents הופיע
ללא בחירה. עכשיו נגזר ב-apply_to_record: עדיפות לגזירה דטרמיניסטית מקידומת
מספר-התיק (1xxx→rishuy, 8xxx→היטל, 9xxx→197 — מקור-אמת לדוקטי ועדת-ערר,
INV-AH rule-based), ובנפילה — סיווג-תוכן של ה-LLM (שדה practice_area חדש
בפרומפט, אנום-סגור) עבור פסקי-בית-משפט שהקידומת שלהם אינה מקודדת תחום.
ממלא רק כשריק (G1 — נרמול במקור, לא תיקון-בקריאה).
2. **שם-יו"ר לא חולץ** (למשל 1132-09-24) — המיזוג היה מגודר על
source_kind=='internal_committee' בלבד, ודילג בשקט על החלטות-ועדה שהועלו
במסלול הפסיקה החיצוני (external_upload + source_type=appeals_committee, כמו
החלטת ת"א מנבו) — היו"ר ישב בבלוק-החתימה אך לא חולץ. עכשיו מגודר על "האם זו
החלטת-ועדה" (source_type/level אפקטיביים), לעולם לא על פסק-בית-משפט. ה-CHECK
כופה non-empty רק ל-internal_committee, לכן כתיבה ל-external בטוחה.
חיזוק-פרומפט (לבקשת היו"ר): chair_name מציין מפורשות את בלוק-החתימה הדו-טורי
(מזכיר↔יו"ר — לקחת את צד-היו"ר) ומזהיר לא לחלץ יו"ר של פסקי-דין **מצוטטים**
בגוף ההחלטה.
UI (לוגיקה-בלבד, פטור משער-העיצוב): edit-sheet מסנכרן-מחדש מהרשומה הטרייה בכל
פתיחה (re-arm על סגירה) ו-usePrecedent עושה poll בזמן חילוץ — כך מילוי-רקע של
practice_area/chair_name מופיע בלי refresh מלא ("הכפתור לא נשאר מסומן").
בדיקות: test_metadata_extract_chair_practice_area.py (6 תרחישי-מיזוג, offline).
Invariants: G1 (נרמול-במקור), G2 (אותו extractor, לא מסלול מקביל),
INV-AH (גזירה דטרמיניסטית מועדפת, abstention כשאין ודאות).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -73,7 +73,18 @@ export function PrecedentEditSheet({ caseLawId, onOpenChange }: Props) {
|
||||
// record arrives (including after save+refetch). Using setState during
|
||||
// render avoids the one-frame flash that useEffect would produce.
|
||||
const [syncedRecordId, setSyncedRecordId] = useState<string | null>(null);
|
||||
if (record && record.id !== syncedRecordId) {
|
||||
// Re-arm the sync on close so the NEXT open re-pulls the latest server record.
|
||||
// The component is always mounted, so without this the form syncs once per
|
||||
// precedent-id for the component's lifetime — and shows stale fields (e.g. a
|
||||
// practice_area / chair_name that background metadata extraction filled AFTER
|
||||
// the last open) until a full page refresh. Resetting on close makes reopening
|
||||
// the sheet reflect the freshest record (which usePrecedent re-fetches while a
|
||||
// row is mid-extraction). Both guards flip to false, so this render-phase
|
||||
// setState terminates.
|
||||
if (!open && syncedRecordId !== null) {
|
||||
setSyncedRecordId(null);
|
||||
}
|
||||
if (open && record && record.id !== syncedRecordId) {
|
||||
setSyncedRecordId(record.id as string);
|
||||
setForm({
|
||||
case_number: record.case_number || "",
|
||||
|
||||
@@ -295,6 +295,15 @@ export function usePrecedent(id: string | null) {
|
||||
),
|
||||
enabled: Boolean(id),
|
||||
staleTime: 30_000,
|
||||
/* Poll while THIS precedent is mid-extraction (text/halacha/metadata) so the
|
||||
* detail catches up after the local MCP drainer fills fields like
|
||||
* practice_area / chair_name — otherwise the open edit sheet shows stale
|
||||
* empties until a hard refresh. Stops once the row settles (mirrors the
|
||||
* list poller in usePrecedents). */
|
||||
refetchInterval: (query) => {
|
||||
const data = query.state.data;
|
||||
return data && isPrecedentActive(data) ? 5000 : false;
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user