feat(missing-precedents): חיפוש-טקסט לפי מראה-מקום בדף פסיקה-חסרה
All checks were successful
G12 Leak-Guard / leak-guard (pull_request) Successful in 5s

הבעיה: בדף /missing-precedents לא ניתן היה לאתר פסיקה חסרה לפי מספר ההחלטה
החסרה עצמה (למשל 85074). השדה היחיד לחיפוש-תיק עשה get_case_by_number על
מספר ה-ערר שבו צוטטה הפסיקה — ולכן הקלדת מספר-הפסיקה החזירה רשימה ריקה,
למרות שהרשומה קיימת (ערר (ת"א 85074-04-25) ... status=open).

התיקון (הרחבת השדה הקיים, ללא עמוד/שדה חדש — בהנחיית חיים):
- db.list_missing_precedents: פרמטר q חדש — ILIKE על mp.citation +
  mp.case_name + cited-in c.case_number (אינדקס-פרמטר יחיד, additive;
  שאר הקוראים לא נוגעים).
- GET /api/missing-precedents: פרמטר q; case_id/case_number נשארים
  מסננים-מדויקים לקוראים תכנותיים.
- web-ui: התווית "תיק (מספר ערר)" → "מספר תיק", placeholder
  "85074 או 1017-03-26"; השדה שולח q (חיפוש חופשי) במקום case_number.
  Debounce 350ms נשמר.

api:types לא חודש: ה-hook בונה את ה-querystring ידנית וה-response לא
השתנה; חידוש מול prod (שעוד לא נפרס) רק היה מושך drift לא-קשור.

בדיקות: tsc --noEmit נקי, eslint נקי על הקבצים שהשתנו, py_compile נקי.

Invariants: G2 (הרחבת היכולת הקיימת, לא מסלול-חיפוש מקביל), INV-IA1
(שער/דף יחיד לפסיקה-חסרה — בלי עמוד חדש), §6 (ללא בליעת-שגיאות).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-12 07:58:29 +00:00
parent 5272ded4f7
commit b49cde7c24
5 changed files with 40 additions and 16 deletions

View File

@@ -31,19 +31,19 @@ const STATUS_CHIPS: { value: StatusFilter; label: string }[] = [
];
export default function MissingPrecedentsPage() {
const [caseNumber, setCaseNumber] = useState("");
const [search, setSearch] = useState("");
const [legalTopic, setLegalTopic] = useState("");
const [filter, setFilter] = useState<StatusFilter>("open");
/* Debounce the filters so the table fires one query after the user stops
* typing — not one per keystroke. Each intermediate value used to
* round-trip to the API (and a non-existent case number errored mid-typing). */
const [caseNumberQ, setCaseNumberQ] = useState("");
* typing — not one per keystroke. The search term matches the gap's own
* מראה-מקום, case name, and cited-in appeal number (server-side ILIKE). */
const [searchQ, setSearchQ] = useState("");
const [legalTopicQ, setLegalTopicQ] = useState("");
useEffect(() => {
const t = setTimeout(() => setCaseNumberQ(caseNumber.trim()), 350);
const t = setTimeout(() => setSearchQ(search.trim()), 350);
return () => clearTimeout(t);
}, [caseNumber]);
}, [search]);
useEffect(() => {
const t = setTimeout(() => setLegalTopicQ(legalTopic.trim()), 350);
return () => clearTimeout(t);
@@ -87,11 +87,11 @@ export default function MissingPrecedentsPage() {
{/* shared filters */}
<div className="flex items-end gap-3 flex-wrap">
<div className="flex-1 min-w-[200px]">
<label className="block text-[0.78rem] text-ink-muted mb-1.5">תיק (מספר ערר)</label>
<label className="block text-[0.78rem] text-ink-muted mb-1.5">מספר תיק</label>
<Input
value={caseNumber}
onChange={(e) => setCaseNumber(e.target.value)}
placeholder="1017-03-26"
value={search}
onChange={(e) => setSearch(e.target.value)}
placeholder="85074 או 1017-03-26"
dir="rtl"
/>
</div>
@@ -137,7 +137,7 @@ export default function MissingPrecedentsPage() {
<MissingPrecedentsTable
status={filter === "all" ? "" : filter}
caseNumber={caseNumberQ || undefined}
q={searchQ || undefined}
legalTopic={legalTopicQ || undefined}
/>