feat: מפת סימבולים ב-get_repo_file — ניווט בקבצים גדולים במקום ניחוש

Merged
AM
2mo ago
+1115-10

✨ תיאור קצר

webapp/app.py הוא 20,035 שורות. סוכן שחיפש בו פונקציה קרא טווח וניחש. עם outline=true הכלי מחזיר את המפה — כל פונקציה וכל מחלקה עם שורת התחלה וסיום — וההמשך הוא lines=[start, end] מדויק במקום ניחוש.

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

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

כלל אחד מייצר את כל המפה

מרחב שמות בפייתון הוא פונקציה או מחלקה, ותו לא. התחילית גדלה רק בגבולות האלה — Class.method, _register_repo_tools.get_repo_file — ואילו if/try/with/for נחצים בלי להוסיף תחילית.

הכלל הזה הוא הפיצ'ר. ירידה רק לרמה העליונה החזירה 9 סימבולים ל-mcp_server/server.py במקום 38, והשאירה את build_mcp כבלוק אטום של 513 שורות שכל כלי ה-MCP חבויים בתוכו — כלומר בדיוק הכישלון שהפיצ'ר בא למנוע, בקובץ שמגדיר את הכלי.

וגרסת ביניים עדיין נכשלה: רקורסיה שירדה רק לתוך גופי פונקציות ומחלקות החמיצה 62 סימבולים ב-webapp/app.py, כי _Missing, _NoCache ו-_NativeThread יושבות בתוך except ImportError. חריג נקודתי למעטרים היה מייצר את אותו באג שכבה עמוק יותר.

קובץלפני הכללאחריומונה בלתי תלוי
mcp_server/server.py93838 ✅
main.py89190190 ✅
github_menu_handler.py121145145 ✅
webapp/app.py413530530 ✅
database/manager.py122176176 ✅

חמש ההחלטות, וכל אחת נמדדה

שורת ההתחלה היא של המעטר. ב-webapp/app.py 203 מתוך 408 הפונקציות ברמה העליונה מעוטרות. טווח שהיה מתחיל ב-def היה מתחיל אחרי @app.route(...) — כלומר מחמיץ את השורה שמזהה את הנתיב.

symbol= מסנן על השם המלא, ללא רישיות. symbol="build_mcp" מחזיר את המרחב ואת כל מה שבתוכו — התנהגות מכוונת ומתועדת. total סופר את ההתאמות אחרי הסינון, כי עליו נשען העימוד. על app.py, symbol="api_db" מחזיר 5 סימבולים במקום 530.

שמות אינם ייחודיים. if/else אינם מרחב שמות, ולכן שתי הגדרות בשני ענפים חולקות שם מלא. קיימים שישה מקרים כאלה בריפו היום, למשל login_required.decorated_function בשורות 3448 ו-3465. שום שלב לא ממפתח לפי שם, והסדר הוא לפי שורת התחלה עם השם כשובר-שוויון יציב.

ה-except הרחב עוטף את ast.parse בלבד. סוג החריגה תלוי-גרסה — בייט אפס הוא SyntaxError ב-3.11 ו-ValueError במקומות אחרים, ו-surrogate לא חוקי הוא UnicodeEncodeError — ולכן מניית סוגים היא הגישה השברירית. מעבר העץ רץ מחוץ ל-try, עם מחסנית מפורשת: באג שלנו נופל בקול במקום להתחפש ל"אין אאוטליין", וקינון עמוק לא יכול לייצר RecursionError מהצד שלנו. error_type מוחזר בתשובה, כי except רחב בלעדיו הורג את היכולת לאבחן.

no_outline הוא status ולא error, בדיוק כמו binary: הקריאה הצליחה, פשוט אין תוכן מהסוג שביקשו. extract_outline מדווחת כשל בערך ההחזרה ולא בזריקה, וזה מוצהר ב-docstring לפי K11 — קורא שבודק רק חריגה היה מציג קובץ שבור כקובץ בלי סימבולים.

🧪 בדיקות

36 טסטים חדשים ב-tests/test_mcp_outline.py.

השלמות נבדקת מול tokenize, לא מול ast.walk. לקסר הוא מונה בלתי תלוי; השוואה לפונקציה אחרת באותה ספרייה שהמימוש בנוי עליה מוכיחה הרבה פחות. הבדיקה רצה על חמישה קבצים אמיתיים מהריפו, ויש טסט שמראה שהמונה עצמו מסוגל להפיל.

שמונה מוטציות, כולן הופלו — כל אחת מייצגת גרסה שבאמת נכתבה בדרך:

מוטציהנופלים
בלי ירידה לעומק19
ירידה לגופי פונקציות בלבד11
המעטר לא נספר3
dedup לפי שם4
except SyntaxError בלבד2
ה-except עוטף גם את המעבר1
total סופר את הקובץ1
per_page מהודק לתקרת העץ1
  • אימות מול mirror אמיתי: ארבעת הקבצים הגדולים מתלכדים עם המונה הבלתי תלוי, והמסלול המלא עובד — symbol="api_db_collections" ← שורות 5421–5481 ← lines= שמחזיר 61 שורות שמתחילות ב-@app.route.
  • טסט אינטגרציה עם git init + clone --mirror ב-tmp_path, בלי נגיעה בעץ העבודה.
  • תוספתיות: בלי outline התשובה זהה לזו של היום.
  • דרך ממשק ה-MCP ולא רק דרך הפונקציה, לפי claude-md-snippets/testing.md כלל 1.
  • tests/test_mcp_*.py — 565 עוברים, אפס נופלים.
  • ⚠️ flake8 אינו מותקן בקונטיינר הזה. הרצתי py_compile ואורך שורות מול max-line-length=120.

ובדרך תוקנה דמת בדיקה צרה: _RecordingRepoBackend.get_file קיבלה רק את החתימה הישנה. יושרה לחוזה האמיתי עם הפרמטרים בסוף, כמו שכבר נעשה שם ל-list_tree — זה הדפוס שמתועד ב-CLAUDE.md.

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

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

📝 סוג שינוי

  • feat: פיצ'ר חדש

✅ צ'קליסט

  • הקוד עוקב אחרי הסגנון
  • בדיקות רצות ועוברות
  • תיעוד עודכן — סעיף mcp-outline חדש ב-docs/mcp-server.rst ומחרוזת התיאור של הכלי
  • לא נוספו ג'ובים חדשים
  • לא נוספו משתני סביבה
  • אין סודות/מפתחות בקוד
  • אין מחיקות מסוכנות
  • הודעת הקומיט תואמת Conventional Commits
  • עיינתי במסמכי אתר התיעוד — AI-MAP.md בתחילת התכנון, ומשם docs/mcp-server.rst, docs/observability/error_codes.rst (שקבע ש-E_* הם אוצר מילים אחר), docs/testing.rst, docs/doc-authoring.rst. וב-amir-bug-patterns: CRITICAL-PATTERNS.md K11 ו-claude-md-snippets/testing.md

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

קריאה קיימת אינה משתנה. בלי outline ההתנהגות זהה, ויש על זה טסט. אין נגיעה ב-services/git_mirror_service.py, בוובאפ, באינדקסר או ב-repo_files.

ast.parse אינו מריץ קוד — נבדק. אאוטליין נשפט מול תקרת ה-10MB כמו קריאת טווח, כי הוא קורא את הקובץ ומחזיר פלט זעיר. app.py עולה כ-250ms פרסינג, ורק כשמבקשים מפה.

האאוטליין מחושב מהבלוב ואינו נשמר. lines ב-repo_files כבר לימד שמידע שמור מתיישן ודרש lines_commit_sha; אאוטליין מיושן חמור יותר — הוא שולח לשורה שכבר לא שם.

לקוח MCP שהיה מחובר לפני הדיפלוי לא יראה את הפרמטרים החדשים עד שיתחבר מחדש.

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

revert של הקומיט מחזיר את המצב במלואו. אין מיגרציה ואין שינוי מצב. הפיצ'ר כבוי כברירת מחדל — מי שלא מעביר outline לא רואה שינוי.

🔗 קישורים

  • ממשיך את #3320, שהוסיף את תקרת ה-10MB לקריאת טווח
  • ואת #3316, שהוסיף את lines=[start, end] שהמפה מזינה

🤖 Generated with Claude Code

https://claude.ai/code/session_0154RpRM1aCgLXCwUqDgywYp


Generated by Claude Code

Summary by Sourcery

Add opt-in symbol maps to repository file retrieval so agents can locate functions and classes in large Python files before requesting exact line ranges.

New Features:

  • Add an optional Python symbol outline to repository file retrieval, including fully qualified function and class names with source ranges.
  • Support case-insensitive symbol filtering and pagination for navigating large outlines.

Bug Fixes:

  • Report unsupported files and parse failures explicitly without changing the existing non-outline read behavior.
  • Prevent conflicting outline and line-range requests and reject outline pages that exceed the output byte budget.

Enhancements:

  • Preserve decorator lines in symbol ranges, include nested definitions across control-flow blocks, and retain duplicate symbol names.
  • Extend repository backend and MCP tool contracts with outline parameters and input normalization.

Documentation:

  • Document outline usage, filtering, pagination, Python-only behavior, and size limits in the MCP server documentation and tool description.

Tests:

  • Add comprehensive outline extraction, pagination, error handling, integration, and real-repository coverage, including independent definition counts and mirror-based MCP tests.

Chores:

  • Update test backends to match the expanded repository file retrieval contract.