Repository navigation
refactor(services): חילוץ מודל הסעיפים המשותף ל-services/doc_sections.py - #3394
Conversation
PR 2 בתוכנית "docs_get_section ל-Markdown". ריפקטור טהור, בלי שום שינוי התנהגות, שמכין את הקרקע לפארסר Markdown (PR 3). מה עבר ומה נשאר --------------- כל מה שאינו תלוי בשפת המקור עבר ל-``services/doc_sections.py``: ``Section``, ``Document``, ``TooManySections``, ``_finalize``, ``normalize_title``, ``find_sections``, ``section_bounds``, ``section_text``, ``direct_subsections``, ``neighbors``, ``build_toc`` ו-``suggest``. ``services/rst_parser.py`` נשאר הפארסר של RST בלבד — זיהוי כותרות, כללי ה-adornment ו-``parse_document`` — ומייצא מחדש את השמות שעברו, כדי שאף קורא קיים לא יישבר. הייצוא-מחדש הוא הפניה לאותו אובייקט, ולכן ``rst_parser.Section is doc_sections.Section`` ו-``except rst_parser.TooManySections`` בסורק ממשיכים לעבוד בדיוק כמו קודם. למה מודול נפרד: שני פארסרים שבונים ``Section`` משלהם ומחשבים ``end_line`` משלהם הם שתי הגדרות לאותו כלל, ומי שיתקן באג באחת מהן יפספס את השנייה. התקדים בריפו הוא ``_lines.py`` ו-``_ceiling.py`` ליד סורקי האאוטליין. ההוכחה: אפס-דיף מדוד -------------------- ``scripts/docs_section_zero_diff.py`` מריץ סוללה דטרמיניסטית של ``docs_get_section`` על כל 208 קובצי ה-RST ב-docs/ ומוציא JSONL + sha256. הסוללה מכסה TOC, כל כותרת עם תת-סקשנים ובלעדיהם, שלוש וריאציות נרמול לכל כותרת, ambiguous_section, section_not_found עם הצעות, וחיתוך עם עמוד שני. 5,840 רשומות, sha256 זהה בין main לענף: 610f831d3b8985bd9101024bec4b0b5aa6efbc1484906f17c09746d4ca7a0f90 והסוללה הוכחה כמסוגלת ליפול: שבע מוטציות (``_finalize``, ``build_toc``, ``section_bounds``, ``suggest``, ושלושת כללי ``normalize_title``) נותנות כל אחת digest שונה. אחת מהן — ביטול ה-``casefold`` — עברה בשקט בגרסה הראשונה, כי הסוללה שאלה כל כותרת בדיוק כפי שה-TOC החזיר אותה ושני צדי ההשוואה עברו את אותו נרמול; משם נוספו וריאציות הנרמול. תיקון מדידה שהשינוי הזה מייתר ----------------------------- ה-docstring של ``mcp_server/outline_scanners/__init__.py`` קיבע "72 מודולים, שלושה מהריפו". המספר נמדד מחדש על שני העצים באותה סביבה: התוספת היא מודול אחד בדיוק (``services.doc_sections``) ואפס מודולים כבדים. המספר הכולל הוסר משם כי הוא תלוי-סביבה — ``backoff_state`` מנסה לייבא ``observability``, ולכן אותו ייבוא נמדד 73 בסביבה שבה זה נכשל ו-330 בסביבה שבה זה מצליח. בדיקות ------ tests/test_doc_sections.py — 19 טסטים חדשים: חמישה שומרי מבנה (הגדרה יחידה, זהות הייצוא-מחדש, איסור ייבוא פארסר, אפס מודולים כבדים, וכיסוי השמות שה-handler משתמש בהם) וארבעה-עשר התנהגותיים שבונים ``Section`` ביד ולא דרך פארסר. כל אחד הוכח כנופל תחת מוטציה מתאימה. tests/test_rst_parser.py לא שונה כלל — הוא עד הרגרסיה של השינוי הזה. 1,114 טסטים ב-tests/test_mcp*.py + test_rst_parser + test_doc_sections עוברים. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JofjowYGDSmyqYvtBxKeJV
There was a problem hiding this comment.
Sorry @amirbiron, you've used your own review budget of 250,000 diff characters for the last 7 days.
You can request another review in 5 days and 3 hours by commenting @sourcery-ai review. Upgrade to get a review now.
|
ⓘ Qodo reviews are paused because your trial has ended. Ask your workspace admin to add credits to resume reviews. Manage billing |
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
🧯 Dangerous deletes guard reportPolicy: see .cursorrules — dangerous deletions are blocked unless wrapped safely. Summary:
Flagged findings (file:line:snippet): Excluded matches (by path pattern) |
Reviewer's Guideהריפקטור מרכז את מודל הסעיפים והלוגיקה המשותפת ב-services/doc_sections.py, בעוד rst_parser נשאר ממוקד בתחביר RST ומייצא את ה-API הישן באמצעות אותן מחלקות ופונקציות. בדיקות מבניות וכלי אפס-דיף מאמתים הן את ארכיטקטורת התלויות והן אי-שינוי ההתנהגות על קורפוס התיעוד. Sequence diagram for backward-compatible RST parsingsequenceDiagram
participant Consumer as Existing consumer
participant RST as rst_parser
participant Shared as doc_sections
Consumer->>RST: parse_document(...)
RST->>Shared: construct Section and Document
Shared-->>RST: shared model objects
RST-->>Consumer: Document
Consumer->>RST: build_toc / find_sections / section_text
RST->>Shared: re-exported callable
Shared-->>Consumer: section results
Consumer->>RST: catch TooManySections
RST-->>Consumer: same shared exception class
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Advanced Run ID: 📒 Files selected for processing (5)
Included review availability: Your plan provides up to 1 included review per hour; 0 remain after this review. 📝 WalkthroughWalkthroughהמודול המשותף Changesריפקטור מודל סעיפי המסמכים
Priority: ➖ Normal Estimated code review effort: 4 (Complex) | ~45 minutes Change: Refactor Sequence Diagram(s)sequenceDiagram
participant main
participant _CorpusBackend
participant docs_handlers
participant rst_parser
participant output
main->>_CorpusBackend: טעינת קובץ RST
_CorpusBackend->>docs_handlers: get_file
docs_handlers->>rst_parser: parse_document
rst_parser-->>docs_handlers: נתוני סעיפים
docs_handlers-->>main: תשובת section או TOC
main->>output: כתיבת JSONL וחישוב SHA-256
Merge Risk: ⚪ Minimal · up to The refactor preserves the existing parser interface and has no identified merge-blocking behavior change. 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches 💡 1📝 Generate docstrings 💡
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. כותרת עולה, ועץ נבנה, Comment |
⏱️ Performance report(No performance test durations collected. Mark tests with |
📖 Documentation PreviewThe documentation has been built successfully!
To view locally:
|
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
…figuration, מספר תלוי-סביבה, ו-.pyc בגיט (#3395) * chore(git): קובצי .pyc יוצאים מניהול גיט אחד-עשר קבצי ``__pycache__/*.cpython-313.pyc`` נכנסו לגיט ב-8098b67e (#3239) למרות ש-``.gitignore`` שורה 2 חוסם את התיקייה. ``git rm --cached`` מוציא אותם מהאינדקס ומשאיר אותם על הדיסק, וה-``.gitignore`` הקיים דואג שהם לא יחזרו כ-untracked. נבדק שאין תלות: כל עשרת האזכורים של ``__pycache__`` בריפו הם החרגות בלבד — ``.ruff.toml``, ``bandit.yaml``, ``.yamllint.yaml``, ``services/code_indexer.py``, ``scripts/audit_config_definitions.py``, ``scripts/find_duplicates.py``, ``github_menu_handler.py``, ``repo_analyzer.py`` ושני טסטים. אף אחד מהם אינו קורא מהתיקייה. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01P1AYmWhLGtpsr7sSdRZVD3 * test(doc_sections): התת-תהליך רץ עם -B ומחוץ לעץ המקור ``test_doc_sections_pulls_no_heavy_modules`` הריץ ``subprocess.run([sys.executable, "-c", code], cwd=_ROOT)`` — כלומר תת-תהליך שכותב ``__pycache__`` לתוך ``services/``, וזה טסט שכותב לעץ המקור. התקדים הנכון כבר קיים בריפו, ב-``tests/test_rst_parser.py``, ושם ההערה מנמקת את שני הדגלים במפורש. השורש היה שהייבוא נשען על ה-``cwd``: הוא עבד רק מפני שהתהליך רץ בשורש הריפו. לכן ``-B`` לבדו לא הספיק — ``sys.path.insert`` עם נתיב מוחלט מנתק את המדידה מעץ העבודה, ורק אז ``cwd=tmp_path`` אפשרי. נמדד, ולא הונח. בקרה מבודדת בלי pytest, על ``services/__pycache__`` ריק: הצורה הישנה כותבת שלושה קבצים (``__init__``, ``backoff_state``, ``doc_sections``), הצורה החדשה כותבת אפס, ותיקיית ה-tmp נשארת ריקה גם היא. ומה שלא השתנה, כדי שלא ייקרא אחרת: בריצת pytest רגילה הדלתא הייתה אפס גם קודם, כי האיסוף עצמו מייבא את אותם מודולים וכותב את אותם קבצים. כלומר זו הפרה של מוסכמה ולא באג נצפה, והערך שלה הוא ביום שבו עץ המקור יהיה לקריאה בלבד — כלל 8 ב-CLAUDE.md. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01P1AYmWhLGtpsr7sSdRZVD3 * docs(configuration): הסרת הבלוק הכפול של Pooling ו-HTTP Clients שלושת הסעיפים "Databases and Cache (Pooling/Timeouts)", "HTTP Clients" ו-"שימוש ב-http_sync" הופיעו פעמיים בקובץ. שניהם נכנסו ב**קומיט אחד**, 171d8f6 (#1015, 23.10.2025), שהכניס את אותו בלוק פעם אחרי "Environment variables" ופעם אחרי "Security" — לפניו הכותרות לא היו בקובץ כלל. המחיר נמדד: מתוך 45 תשובות ``ambiguous_section`` שהכלי ``docs_get_section`` מחזיר על כל 208 קובצי ה-RST, 25 הגיעו מהקובץ הזה לבדו. הכפילות גם חצתה את נרמול הכותרות — ``normalize_title`` מאחד מקפים, ולכן ``שימוש ב‑http_sync`` עם U+2011 ו-``שימוש ב-http_sync`` עם מקף ASCII התנגשו זה בזה. **שני העותקים הושוו שורה-שורה לפני המחיקה, והם אינם זהים** — אבל אף הבדל אינו הבדל בתוכן: פיסוק ב-``REDIS_URL``, ניסוח ב-``.. note::`` ("לא להשתמש" מול "אל תשתמשו", גרשיים עבריים מול מרכאה), והמקף בכותרת. נשאר העותק הראשון **מילה במילה**, כי הוא במקום הנכון מבנית — עם שאר סעיפי הקונפיגורציה, והוא היחיד שמלווה ב-"שימוש ב-http_async" שאין לו כפילות. שבע-עשרה מתוך תשע-עשרה השורות שנמחקו קיימות בו כלשונן, והשתיים הנותרות הן שתי וריאציות הניסוח. עוגנים — נבדק ולא הונח: ``autosectionlabel`` אינו מופעל ב-``conf.py``, ולכן לכותרות אין לייבלים אוטומטיים. העוגן המפורש היחיד בקובץ הוא ``.. _config-error-signatures:``, שיושב הרבה מתחת לבלוק שנמחק, ואליו מפנה ``docs/observability/log-aggregator.rst``. שאר ההפניות הנכנסות הן ``:doc:`` לעמוד כולו. אימות: הספירה הורצה מחדש על כל 208 הקבצים — הקובץ הזה ירד מ-25 ל-**0**, והסך הכול מ-45 ל-20 (הנותרים הם ``development/tools.rst`` ו- ``observability/query-performance-profiler.rst``, שלא נגענו בהם). ובנייה מלאה של Sphinx עם ``-W --keep-going`` עברה באפס אזהרות. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01P1AYmWhLGtpsr7sSdRZVD3 * docs(mcp): משקל הייבוא של הסורק מתואר, ולא נספר ה-docstring של ``outline_scanners/__init__.py`` קבע ש-``from services import rst_parser`` מושך "**ארבעה** מודולים מהריפו", ומנה אותם בשמם — וסגר ב"מהריפו רק מודולים שרשומים כאן בשמם". שתי הטענות אינן נכונות בסביבה שבה ``structlog`` מותקן. נמדד בשתי סביבות באותו עץ: - **בלי** ``structlog``: 73 מודולים, ומהריפו ארבעה — שרשרת ה-``services``. - **עם** ``structlog``: 330 מודולים, ומהריפו שבעה — אותם ארבעה ועוד ``observability``, ``monitoring`` ו-``monitoring.error_signatures``. השרשרת: ``services/__init__.py`` מייבא ``state`` מ-``backoff_state``, ששורה 16 בו **מנסה** לייבא ``observability``; ו-``observability.py`` מייבא ``structlog`` בקשיחות בשורה 22 ומנסה ``monitoring.error_signatures`` בשורה 28. כלומר הזנב הזה תלוי במה שמותקן בסביבה, לא בשורת קוד — וזה בדיוק המבחן שב-``docs/doc-authoring.rst``: מספר שיכול להשתנות בלי שאף שורת קוד תשתנה אינו ערך שנאכף. הניסוח החדש מתאר מה נטען ולמה — חלק קבוע וזנב מותנה — ואינו קובע מספר ואינו סוגר רשימה. האינווריאנט הנושא נשאר, והוא זה שנמדד בשתי הסביבות: **אפס מודולים כבדים**. ותוקן גם דיוק שני: הטסט שאוכף את האינווריאנט מודד את ``services.doc_sections``, לא את ``rst_parser``, וזה נכתב עכשיו כפער מוצהר במקום להשתמע ככיסוי. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01P1AYmWhLGtpsr7sSdRZVD3 --------- Co-authored-by: Claude <noreply@anthropic.com>
✨ תיאור קצר
PR 2 בתוכנית "שלב 1 —
docs_get_sectionל-Markdown". כל מה שאינו תלוי בשפת המקור —Section,Document, וכל פונקציות העץ — עובר מ-services/rst_parser.pyלמודול חדשservices/doc_sections.py, ו-rst_parserמייצא אותם מחדש. ריפקטור טהור: אפס שינוי התנהגות, וההוכחה לכך היא אפס-דיף מדוד ולא "הטסטים עוברים".הסיבה: PR 3 מוסיף פארסר Markdown שבונה לתוך אותו חוזה בדיוק. שני פארסרים שבונים
Sectionמשלהם ומחשביםend_lineמשלהם הם שתי הגדרות לאותו כלל, ומי שיתקן באג בחישוב ההיררכיה יתקן אותו באחד משניהם והשני יסטה בשקט.📦 שינויים עיקריים
פירוט:
services/doc_sections.py(חדש) —Section,Document,TooManySections,_finalize,normalize_title,find_sections,section_bounds,section_text,direct_subsections,neighbors,build_toc,suggest. ייבוא קל בלבד:re,dataclasses,difflib,typing.services/rst_parser.py— נשאר הפארסר של RST בלבד (זיהוי כותרות, כללי ה-adornment,parse_document), ומייצא מחדש את השמות שעברו דרך__all__.tests/test_doc_sections.py(חדש) — 19 טסטים.scripts/docs_section_zero_diff.py(חדש) — כלי ההוכחה. ישמש שוב ב-PR 4, שגם הוא דורש אפס-דיף על RST.mcp_server/outline_scanners/__init__.py— תיקון מדידה שהשינוי מייתר (פירוט למטה).מה שומר על הקוראים הקיימים
הייצוא-מחדש הוא הפניה לאותו אובייקט ולא עותק, ולכן
rst_parser.Section is doc_sections.Section. זה מה שמחזיק שני דברים שהיו נשברים בשקט אילו מישהו היה מגדיר מחדש במקום לייבא:mcp_server/outline_scanners/rst.pyתופסexcept rst_parser.TooManySections— שתי מחלקות שונות היו גורמות ל-exceptלפספס, והחריגה הייתה עולה מהסורק במקום להיהפך ל-too_many_symbols.tests/test_mcp_outline.pyמחליף אתrst_parser.Sectionבמונה כדי לוודא שהתקרה עוצרת את הפרסור.mcp_server/docs_handlers.pyלא שונה כלל בשלב הזה (הוא משתנה ב-PR 5).🧪 בדיקות
ההוכחה המרכזית: אפס-דיף מול main
scripts/docs_section_zero_diff.pyמריץ סוללה דטרמיניסטית שלdocs_get_sectionעל כל 208 קובצי ה-RST ב-docs/ומוציא JSONL קנוני + sha256. הורץ פעמיים — פעם ב-worktree שלmainופעם על הענף, על אותה תיקיית קורפוס בדיוק כדי ששינוי בתיעוד לא יתחפש לשינוי התנהגות:610f831d3b8985bd9101024bec4b0b5aa6efbc1484906f17c09746d4ca7a0f90610f831d3b8985bd9101024bec4b0b5aa6efbc1484906f17c09746d4ca7a0f90diffפילוח מסלולי התשובה שנכסו:
toc208 ·section5,166 ·section_not_found416 ·ambiguous_section45 ·missing_path3 ·repo_not_allowed1 ·not_found1. בנוסף: 208 תשובות עםsuggestionsלא ריקות, 239 עםtruncated, 685 עם תת-סקשנים, 2,218 עם שכנים.והסוללה הוכחה כמסוגלת ליפול
שבע מוטציות, כל אחת נותנת digest שונה:
610f831d…_finalize—<=ל-<e4ab446d…normalize_titleבליcasefold86ef5bd7…normalize_titleבלי כיווץ רווחים360f10a8…normalize_titleבלי איחוד מקפים39d045cd…build_tocסופר תווים ולא בייטים639b5290…suggestעםcutoff=0.9c016b814…section_boundsoff-by-onefda5448e…ואחת מהן חשפה חור אמיתי בסוללה. בגרסה הראשונה ביטול ה-
casefoldלא שינה את ה-digest בכלל — כי הסוללה שאלה כל כותרת בדיוק כפי שה-TOC החזיר אותה, ואז שני צדי ההשוואה עוברים את אותו נרמול. כלומר מוטציה אמיתית עברה את ההוכחה בשקט. משם נוספו שלוש וריאציות נרמול לכל כותרת (swapcase, רווחים, מקף ארוך), והמספר עלה מ-3,663 ל-5,840 רשומות.טסטים
tests/test_rst_parser.py— לא שונה כלל. הוא עד הרגרסיה של השינוי הזה.tests/test_doc_sections.py— 19 חדשים. חמישה שומרי מבנה שנבדקים על המקור ולא על ההתנהגות (הגדרה יחידה לכל שם, זהות הייצוא-מחדש, איסור ייבוא פארסר אוmcp_server, אפס מודולים כבדים בתת-תהליך נקי, וכיסוי כל השמות ש-docs_handlersמשתמש בהם — נגזר מה-AST של הצרכן ולא מרשימה מוקלדת). וארבעה-עשר התנהגותיים שבוניםSectionביד ולא דרך פארסר, כיtest_rst_parser.pyכבר בודק את המודל דרך RST.כל טסט חדש הוכח כנופל תחת מוטציה מתאימה, אחד-אחד ובבידוד. שתי מוטציות נתפסו בתחילה על ידי טסט אחר בגלל
-x, ולכן הורצו שוב לבד.1,114 טסטים ב-
tests/test_mcp*.py+test_rst_parser.py+test_doc_sections.py— עוברים.Unit
Integration
Manual
באג שנמצא בטסט שלי עצמו, תוך כדי
test_doc_sections_imports_no_parser_and_no_mcpבדק בתחילה אתnode.moduleבלבד. לכןfrom services import rst_parser— בדיוק הסגנון הנהוג בריפו, ולכן הצורה הסבירה ביותר שמישהו יכתוב — התחמק ממנו: שם המודול שם הואservices, והפארסר יושב ב-names. נמדד שהמוטציה עברה, ונתפסה רק במקרה על ידי ייבוא מעגלי שהפיל טסט אחר. תוקן לאסוף גם את השמות המיובאים.🧪 בדיקות נדרשות ב‑PR
📝 סוג שינוי
✅ צ'קליסט
flake8נקי על כל חמשת הקבצים;isortנקי;mypyללא שגיאות חדשות (ראו "השפעות/סיכונים")--outשנמסר לו, ואינו מוחק דברdocs/mcp-server.rst(סעיפיmcp-outline,mcp-limits) | המשפט: "אל תערבב, ואל תמציא ערך חדש בלי לעדכן אתdocs/mcp-server.rst" — נבדק שאף ערךstatus/error/reasonלא נוסף ולא השתנה, ולכן אין מה לעדכןדפוסי באגים — מה נקרא ומה נמצא
claude-md-snippets/testing.md— נקרא לפני כתיבת הטסטים. כלל 5 ("הרץ בדיקה חדשה ווּדא שהיא נופלת") הוא מה שהוביל לכל מטריצות המוטציות כאן, ולגילוי החור ב-normalize_titleובטסט הייבוא.BY-STACK/hebrew-source.mdH6 — נקרא כיbuild_tocמודדlen(...encode("utf-8")). המסקנה: זה False Positive מפורש לפי המסמך ("מדידה שבאמת עוסקת בגודל אחסון או בגודל תעבורה"), כיapprox_bytesמשרת את תקציב הבתים של התשובה. אין באג — וזה עדיין קובע בטסט (test_build_toc_measures_bytes_and_not_characters, על עברית דווקא, כי באנגלית שתי היחידות זהות והבדיקה הייתה חסרת ערך). נבדק גם שהחיתוך במסלול עצמו עקבי:docs_handlersחותך בתווים והשדות נקראיםmax_chars/remaining_chars.CRITICAL-PATTERNS.mdK11 — לא רלוונטי ל-PR הזה ואומר זאת במפורש: הכלל נדלק לפני עטיפת קריאה ב-try/except, וה-PR הזה אינו מוסיף אףtry/except.line-number-coupling— ההפניות בתיעוד שנכתב כאן הן לשמות סימבולים, לא למספרי שורות.🧩 השפעות/סיכונים
mypy: שתי שגיאותarg-typeב-mcp_server/docs_handlers.py:130,136— קיימות בדיוק כך גם ב-main, בקוד שה-PR הזה לא נוגע בו, ו-CI חוסם רק עלattr-defined/return-value.black:services/doc_sections.pyנשמר זהה לקוד שממנו הועבר ולא עבר פירמוט, כדי שהדיף יישאר "העברה" ולא "העברה + פירמוט". זה עקבי עם הריפו:rst_parser.pyעצמו אינו black-clean ב-main, וכך גם 5 מתוך 6 קבצים מקבילים שנבדקו; ב-CI black רץ עם|| true.__all__ב-rst_parserאינו קישוט: בלעדיו שמונה מהשמות אינם נקראים בגוף המודול ו-pyflakes מדווחF401על כל אחד (נמדד — בדיוק שמונה).# noqaשמונה פעמים היה מסתיר את האזהרה במקום להצהיר על הכוונה. נבדק ששני מצבי הסחיפה מכוסים: הסרה מרשימת הייבוא מפילה טסט, והסרה מ-__all__בלבד מדליקהF401.תיקון מדידה שהשינוי הזה מייתר
ה-docstring של
mcp_server/outline_scanners/__init__.pyקיבע "72 מודולים, שלושה מהריפו" כנימוק להיתר שהסורק מייבא מ-services. השינוי מוסיף מודול לשרשרת, ולכן המספר נמדד מחדש על שני העצים באותה סביבה: התוספת היא מודול אחד בדיוק (services.doc_sections) ואפס מודולים כבדים.והמספר הכולל הוסר משם, כי הוא תלוי-סביבה ולא תלוי-קוד:
services/backoff_state.pyמנסה לייבאobservability, ולכן אותו ייבוא נמדד 73 מודולים בסביבה שבה זה נכשל ו-330 בסביבה שבה זה מצליח — פי ארבעה וחצי, בלי ששורת קוד אחת השתנתה. מה שמחזיק הוא האינווריאנט (אפס כבדים, ומהריפו רק מה שרשום בשמו), ולא מספר שמתיישן בלי שאיש ישים לב.🔗 קישורים
services/md_parser.py+ נעיצתmarkdown-it-py.docs_get_sectionהיה מנגנון שני לאותה תקרה.🧯 סיכון / החזרה לאחור (Rollback)
git revertשל קומיט אחד. אין מיגרציה, אין שינוי סכימה, אין שינוי קונפיג, ואין צרכן חיצוני שהחוזה שלו זז.🤖 Generated with Claude Code
https://claude.ai/code/session_01JofjowYGDSmyqYvtBxKeJV
Generated by Claude Code