מחיקת מסמך משאירה בלוב יתום ב-MinIO — נמחק רק הנתיב המקומי #460

Open
opened 2026-08-05 12:02:46 +00:00 by chaim · 0 comments
Owner

What & Why

DELETE /api/cases/{case_number}/documents/{doc_id} (web/app.py:6304) מוחק את הקובץ כך:

file_path = doc.get("file_path")
if file_path:
    import pathlib
    p = pathlib.Path(file_path)
    if p.exists():
        p.unlink(missing_ok=True)

זהו נתיב-דיסק מקומי בלבד. אבל אחרי הגירת X14 הייצור רץ STORAGE_BACKEND=s3 (אומת בקונטיינר gyjo0mtw2c42ej3xxvbz8zio), כלומר הבלוב האמיתי יושב ב-MinIO. p.exists() מחזיר False, ה-unlink לא עושה כלום, והבלוב נשאר ב-MinIO לנצח בעוד השורה ב-DB נעלמת — אין יותר דרך למצוא אותו.

השכבה הנכונה כבר קיימת ולא נקראת: storage.delete(key, bucket=...) ב-mcp-server/src/legal_mcp/services/storage.py:465, עם מימוש לשני ה-backends (fs ב-384, s3 ב-386).

הקשר

התגלה 2026-08-05 בעת מחיקת "כתב ערר" מתיק 1069-04-26 (מסמך של 407K תווים, 618 chunks, 336 image embeddings). ה-DB נוקה כראוי דרך CASCADE — הבלוב לא.

נזק: דליפת אחסון שקטה. כל מסמך שנמחק מאז המעבר ל-s3-only השאיר בלוב. שווה גם סקריפט-ניקוי חד-פעמי שמאתר בלובים ב-MinIO שאין להם שורה ב-documents.

⚠️ WORM: לשני מסמכים סופיים יש נעילת-WORM ל-7 שנים (ראה X14) — מחיקת בלוב חייבת לכבד זאת ולא להיכשל בקול.

Acceptance Criteria

  • api_delete_document קורא ל-storage.delete() עם המפתח של המסמך, ולא רק ל-pathlib.unlink.
  • מחיקה תחת STORAGE_BACKEND=s3 מסירה את האובייקט מ-MinIO — מאומת ב-mcli ls לפני/אחרי.
  • כשל במחיקת הבלוב מדווח (logger.warning + שדה בתשובה) ולא נבלע — §6. מחיקת שורת-ה-DB לא נחסמת בגללו.
  • אובייקט נעול-WORM מחזיר שגיאה ברורה במקום כשל אטום.
  • טסט: מסמך שנמחק תחת backend מדומה → storage.delete נקרא פעם אחת עם המפתח הנכון.
  • (נפרד, אופציונלי) סקריפט שמאתר בלובים יתומים שנוצרו לפני התיקון.
## What & Why `DELETE /api/cases/{case_number}/documents/{doc_id}` (`web/app.py:6304`) מוחק את הקובץ כך: ```python file_path = doc.get("file_path") if file_path: import pathlib p = pathlib.Path(file_path) if p.exists(): p.unlink(missing_ok=True) ``` זהו נתיב-דיסק מקומי בלבד. אבל אחרי הגירת X14 **הייצור רץ `STORAGE_BACKEND=s3`** (אומת בקונטיינר `gyjo0mtw2c42ej3xxvbz8zio`), כלומר הבלוב האמיתי יושב ב-MinIO. `p.exists()` מחזיר False, ה-`unlink` לא עושה כלום, ו**הבלוב נשאר ב-MinIO לנצח** בעוד השורה ב-DB נעלמת — אין יותר דרך למצוא אותו. השכבה הנכונה כבר קיימת ולא נקראת: `storage.delete(key, bucket=...)` ב-`mcp-server/src/legal_mcp/services/storage.py:465`, עם מימוש לשני ה-backends (`fs` ב-384, `s3` ב-386). ## הקשר התגלה 2026-08-05 בעת מחיקת "כתב ערר" מתיק 1069-04-26 (מסמך של 407K תווים, 618 chunks, 336 image embeddings). ה-DB נוקה כראוי דרך CASCADE — הבלוב לא. **נזק:** דליפת אחסון שקטה. כל מסמך שנמחק מאז המעבר ל-s3-only השאיר בלוב. שווה גם סקריפט-ניקוי חד-פעמי שמאתר בלובים ב-MinIO שאין להם שורה ב-`documents`. **⚠️ WORM:** לשני מסמכים סופיים יש נעילת-WORM ל-7 שנים (ראה X14) — מחיקת בלוב חייבת לכבד זאת ולא להיכשל בקול. ## Acceptance Criteria - [ ] `api_delete_document` קורא ל-`storage.delete()` עם המפתח של המסמך, ולא רק ל-`pathlib.unlink`. - [ ] מחיקה תחת `STORAGE_BACKEND=s3` מסירה את האובייקט מ-MinIO — מאומת ב-`mcli ls` לפני/אחרי. - [ ] כשל במחיקת הבלוב **מדווח** (`logger.warning` + שדה בתשובה) ולא נבלע — §6. מחיקת שורת-ה-DB לא נחסמת בגללו. - [ ] אובייקט נעול-WORM מחזיר שגיאה ברורה במקום כשל אטום. - [ ] טסט: מסמך שנמחק תחת backend מדומה → `storage.delete` נקרא פעם אחת עם המפתח הנכון. - [ ] (נפרד, אופציונלי) סקריפט שמאתר בלובים יתומים שנוצרו לפני התיקון.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: ezer-mishpati/legal-ai#460