feat: קריאת טווח שורות מקבלת תקרה משלה (10MB) במקום ה-500KB

Merged
AM
2mo ago
+186-14

✨ תיאור קצר

codekeeper_get_repo_file סירב לכל קובץ מעל 500KB, עם lines ובלעדיו, כי בדיקת הגודל רצה ב-get_file_at_commit לפני שהתוכן מפוענח ונחתך. webapp/app.py בן 805,594 הבייטים — הקובץ שהכי הרבה עובדים עליו כאן — היה פשוט בלתי קריא דרך הכלי.

מעכשיו קריאת טווח נשפטת מול תקרה משלה. סוגר את #3317.

ה-PR הזה התחיל כתיקון נוסח בלבד (הזזת הסוגריים בתיאור). כשהוחלט לאפשר את הקריאה בפועל, המשפט שתיקנתי הפך לשקרי בעצמו — ולכן שני הדברים נכנסו יחד ולא בזה אחר זה.

📦 שינויים עיקריים

  • קוד (Backend)
  • בוט טלגרם
  • מסד נתונים/מיגרציות
  • תיעוד (docs/, README, מחרוזת התיאור)
  • DevOps/CI/CD

איך זה מומש — הדרך הפשוטה מהאישו

max_size כבר היה פרמטר של get_file_at_commit עם ברירת מחדל. אז השינוי כולו יושב ב-mcp_server/repo_backend.get_file:

size_kwargs = {"max_size": RANGE_READ_MAX_BYTES} if lines is not None else {}

בלי lines הפרמטר לא מועבר כלל, כך שברירת המחדל של שירות המראה נשארת מקור האמת היחיד ל-500KB ולא נוצר מספר שני שצריך לסנכרן. services/git_mirror_service.py לא נגע, webapp/routes/repo_browser.py לא נגע, והעוזר המשותף שחותך את הטווח נשאר במקומו — כלומר האינווריאנטה מ-#3316, ששני הכלים חולקים סמנטיקה מדויקת, מוחזקת.

למה תקרה אחרת ולא ביטול

הבלוב עדיין נקרא ומפוענח במלואו לפני החיתוך — זה בדיוק מה שמדדתי באישו. "בלי תקרה" פירושו שקובץ פתולוגי בריפו יגיע ל-RAM כמו שהוא.

קובץגודלשיא זיכרון
webapp/app.py0.8MB5.5MB
md_preview.bundle.js6.6MB35.7MB

קריאה ופענוח עולים בערך פי שלושה מגודל הקובץ. 10MB חוסמים את השיא סביב 30MB, ונותנים פי 12 מרווח מעל הקובץ הגדול ביותר שבאמת קוראים (app.py). המספר הזה הוא החלטת מדיניות של שכבת ה-MCP — לכן הוא ב-repo_backend ולא בשירות המראה, והוא שינוי של שורה אחת אם תרצה אחרת.

ולידציית הטווח עברה לפני הקריאה

הרמת התקרה הפכה את זה לעלות אמיתית: טווח פגום כמו [9, 2] היה גורם לקריאה ולפענוח של עד 10MB רק כדי להיפסל בסוף. כשהתקרה הייתה 500KB זה לא היה משנה, כי קובץ גדול נפסל ממילא. הבדיקה טהורה וזולה, אז היא רצה ראשונה — וזה חלק מהשינוי, לא שיפור נפרד.

🧪 בדיקות

  • אימות מול mirror אמיתי (git clone --mirror של הריפו הזה), ולא מול דמה:
    • webapp/app.py עם lines=[5431, 5436] ← status: ok, total_lines: 20036, התוכן נכון
    • אותו קובץ בלי lines ← status: too_large, max: 512000
    • md_preview.bundle.js.map (11.7MB) עם lines ← too_large, max: 10485760
    • קובץ בינארי עם lines ← status: binary, מטא-דאטה בלבד
    • שיא זיכרון לקריאת טווח מ-app.py: 5.4MB
  • חמישה טסטים חדשים ב-tests/test_mcp_additive_params.py, עם דמה שרושמת את max_size שהועבר בפועל
  • מוטציה — חמש, כולן הפילו את מה שנועדו:
    1. לא מעבירים max_size כלל (חזרה למצב שב-#3317)
    2. מעבירים את התקרה תמיד — שובר את הקריאה המלאה ואת הוובאפ
    3. ביטול התקרה במקום החלפתה
    4. ולידציית הטווח חוזרת לרוץ אחרי הקריאה
    5. התיאור מזכיר תקרה אחת במקום שתיים
  • tests/test_mcp_*.py — 528 עוברים, אפס נופלים
  • ⚠️ flake8 אינו מותקן בקונטיינר הזה. הרצתי py_compile ואורך שורות מול max-line-length=120

ובדרך תפסתי טסט שלי ששיקר: קראתי לו ..._before_the_cap_is_lifted בזמן שהקובץ כן נקרא ורק אחר כך הטווח נפסל. mirror.calls == [] הוא מה שהפך את ההבטחה לבדיקה.

🧪 בדיקות נדרשות ב‑PR

  • 🔍 Code Quality & Security
  • Unit Tests (3.11)
  • Unit Tests (3.12)

📝 סוג שינוי

  • feat: פיצ'ר חדש

✅ צ'קליסט

  • הקוד עוקב אחרי הסגנון
  • בדיקות רצות ועוברות
  • תיעוד עודכן — docs/mcp-server.rst (הסייג בסעיף mcp-line-range אמר את ההפך ותוקן; טבלת הכלים), mcp_server/README.md, ומחרוזת התיאור של הכלי
  • לא נוספו ג'ובים חדשים
  • לא נוספו משתני סביבה
  • אין סודות/מפתחות בקוד
  • אין מחיקות מסוכנות
  • הודעת הקומיט תואמת Conventional Commits
  • עיינתי במסמכי אתר התיעוד — docs/mcp-server.rst, סעיפים mcp-line-range וטבלת הכלים

🧩 השפעות/סיכונים

קריאה קיימת אינה משתנה. בלי lines ההתנהגות זהה בבייט, ולוובאפ אין שום שינוי — יש על שניהם טסט.

קריאת טווח מקובץ גדול צורכת עכשיו עד ~30MB שיא רגעי במקום להיכשל מיד. בשירות שמשרת משתמש אחד זה זניח, וזו בדיוק ההחלטה שהתקבלה באישו אחרי שהמספרים נמדדו.

לקוח MCP שהיה מחובר לפני הדיפלוי לא יראה את התיאור החדש עד שיתחבר מחדש — אבל ההתנהגות תעבוד לו בכל מקרה.

🧯 סיכון / החזרה לאחור (Rollback)

revert של הקומיטים מחזיר את המצב במלואו. אין מיגרציה ואין שינוי מצב מתמשך. ולחלופין, RANGE_READ_MAX_BYTES = 512_000 מחזיר את ההתנהגות הישנה בשורה אחת.

🔗 קישורים

  • סוגר את #3317
  • הנוסח שנוצר ב-#3316, שהוסיף את lines

🤖 Generated with Claude Code

https://claude.ai/code/session_0154RpRM1aCgLXCwUqDgywYp