Doc Authoring Guide (Sphinx/RTD)

summary:

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

מטרות

  • בנייה ללא אזהרות (-W --keep-going / fail_on_warning: true).

  • עקביות בכותרות, קישורים ועוגנים.

מדיניות

  • עמודי סקירה חופפים: הוסיפו :noindex: (api, database, handlers, services, configuration).

  • autodoc_mock_imports: רשימת מודולים כבדים/לא זמינים בזמן build.

  • אין להריץ קוד בזמן import ברמת מודול.

  • עמוד שאינו אמור להתפרסם — ל-**``exclude_patterns``**, לא ליתום. עמוד שאינו רשום באף toctree מייצר document isn't included in any toctree, ומכיוון ש-RTD נכשל על אזהרות זה מפיל את הבילד. exclude_patterns ב-docs/conf.py מרכז את העמודים שהוחרגו בכוונה — למשל כפילויות .md/.rst כשה-MyST פעיל. לפני שמוסיפים החרגה, ודאו שהעמוד באמת לא אמור להיות בתוכן העניינים.

הצהרת תקציר בראש העמוד

  • כל עמוד ידני מצהיר על תקציר בראשו. AI-MAP.md — מפת הניווט לסוכני AI — קורא את ההצהרה הזו ולא מנסה לנחש אותה מהגוף.

  • ב-.rst: שדה :summary: מיד מתחת לקו הכותרת. Sphinx מכבה את doctitle_xform, ולכן אין קידום ל-docinfo — השדה מרונדר במקומו, כ-field-list מתחת ל-H1, ו**מוצג בעמוד**. הגלוּת מכוונת: תקציר שרואים הוא תקציר שמתיישן בקול.

  • ב-.md: מפתח summary ב-front matter, שנקרא ב-yaml.safe_load בדיוק כמו ש-MyST קורא אותו.

  • אין הצהרה ← המפה מציגה את הכותרת בלבד. python3 scripts/generate_ai_map.py --check מתריע על עמודים כאלה ואינו מפיל את הבנייה.

  • משפט אחד או שניים, בגוף ההווה, שעונים על ”מה יש בעמוד הזה“. שורת המפה נחתכת ב-220 תווים; ההצהרה בעמוד נשארת מלאה.

  • אל תתחילו בשם העמוד. שורת המפה היא נתיב — **כותרת**: תקציר, כך שהכותרת כבר שם; תקציר שפותח בה מייצר כפילות מיידית (Playbook קצר להתראות: פלייבוק קצר להתראות: ...). התחילו בתוכן.

  • אל תכתבו בתקציר ספירה או הבטחת יכולת. ”שבעה מסלולי API“, ”28 אייקונים“, ”דוגמאות מוכנות להרצה“, ”תומך בחיפוש סמנטי“ — כל אלה טענות שדורשות אימות מול הקוד, והן מתיישנות בלי שאיש ישים לב. שלושה סבבי ריוויו רצופים בפרויקט הזה נפלו בדיוק על זה: ספירה שהשתנתה, קוד עם ... שהוצג כרץ, ו-SearchType שקיים ב-enum ואינו ממומש. תארו מה יש בעמוד, לא כמה ולא מה עובד. tests/test_doc_summary_style.py אוכף את זה על ספירה במילים ועל ספירה בספרות שאחריה מילה עברית — והוא רשת לצורות הנפוצות, לא אישור שהתקציר נכון; מה שהוא במפורש אינו תופס מתועד ב-docstring שלו.

  • אל תשאירו כותרת יתומה. אם ההצהרה מחליפה פסקת פתיחה והסעיף שהכיל אותה נשאר ריק — מחקו גם את הכותרת. סעיף ריק מרונדר בעמוד כשורה ללא גוף.

  • למה הצהרה ולא חילוץ אוטומטי: הגרסה הקודמת חילצה את פסקת הפרוזה הראשונה, וכדי לעשות זאת מימשה חלקים מ-GFM ומ-RST ביד. ארבעה סבבי ריוויו רצופים מצאו שם מקרי קצה — כולל תקציר שיצא טבלה שלמה ותקציר שיצא ריק. מי שכתב את העמוד יודע מה התקציר.

ספירות בפרוזה: ספירת מופעים לעומת ערך שנאכף

הכלל שלמעלה אוסר ספירה בתקציר, אבל הסיבה אינה מוגבלת לשם: כל מספר שנכתב בפרוזה מתיישן באותה שקט. ההבחנה שמכריעה אינה איפה המספר יושב אלא מי אחראי עליו.

  • ספירת מופעים — אל תכתבו. ”בשתי ההפניות לעמוד הזה“, ”28 אייקונים“, ”שבעה מסלולי API“. אף אחד לא שומר על המספר הזה: כל הוספה שוברת אותו, ושום בדיקה לא מתריעה. נסחו בלי כמות — ”בכל מקום שבו העמוד נוגע בנימוק הנדסי“ נכון גם אחרי התוספת הבאה.

  • ערך שנאכף — כן תעדו. ”20 פתקים לקובץ“, ”תקרה של 1000 פתקים למשתמש“, ”עד 500KB לקובץ“. המספר הזה חי בקוד ונאכף בו, ולכן הוא אינו נסחף מעצמו — ומי שקורא את התיעוד חייב אותו. שינוי שלו הוא שינוי מוצר שממילא מחייב עדכון תיעוד.

המבחן: אם המספר יכול להשתנות בלי שאף שורת קוד תשתנה — הוא ספירת מופעים, ואין לכתוב אותו.

tests/test_doc_summary_style.py אוכף את הכלל על תקצירים בלבד. בפרוזה אין אכיפה אוטומטית, וזה הפער שכבר נתפס כאן: הכלל הזה נוסח אחרי שריוויוור מצא ספירה שגויה בפרוזה של עמוד — בתוך סעיף שכל נושאו דיוק בתיעוד.

הטמעת קוד מהמקור (literalinclude)

  • אסור למען לפי מספרי שורות (:lines:) — הקוד זז והתיעוד ממשיך להציג את הטווח הישן בלי שום אזהרה. זה דפוס line-number-coupling (ראו amir-bug-patterns), והוא כבר קרה כאן: בלוק שהצביע על main.py:739 הציג פנימיות של פונקציה אחרת, במרחק 2,900 שורות מהיעד.

  • פונקציה או מחלקה שלמה ← :pyobject:. הקוד נמשך לפי שם בכל בנייה, ושינוי שם מפיל את הבנייה ברעש.

  • קטע בתוך פונקציה ← הערות סימון בקוד בפורמט # docs:<שם>:start / # docs:<שם>:end, ומיעון ב-:start-after: / :end-before:. הערת ה-start חייבת לומר שהתיעוד תלוי בה ולאיזה דף — אחרת הריפקטור הבא ימחק אותה כהערה סתומה.

  • marker חסר מפיל את הבנייה תחת -W (אזהרת docutils, שאינה מושתקת בקונפיגורציה) — נבדק. marker כפול מסוכן יותר: הבלוק ירונדר מהמופע הראשון בלי אזהרה, ולכן כל שם מופיע פעם אחת בדיוק. tests/test_docs_literalinclude_anchors.py אוכף את שני הכללים.

טיפים מהירים

  • אל תריצו את הבנייה המלאה לוקאלית כדבר שבשגרה — אבל דעו מי בדיוק תופס את האזהרות, כי לא כל בדיקה תופסת. ה-GitHub Action שרץ על PR הוא documentation.yml, והוא בונה בלי -W (sphinx -b html . _build/html --keep-going -j auto), כלומר אינו נכשל על אזהרות. docs.yml כן מריץ -W, אבל הוא workflow_dispatch — ידני בלבד, ובכוונה, כדי לא לחפוף. מי שתופס אזהרות על PR הוא Read the Docs: .readthedocs.yaml מגדיר fail_on_warning: true, וה-check שלו יורד לאדום. לכן בנייה מקומית של פרוזה בעמוד קיים היא בזבוז — RTD יתפוס.

  • אל תסיקו מזה ש-RTD שקול לבנייה המקומית. הוא מתקין docs/requirements.txt משלו ורץ בסביבה אחרת, כך שגרסת Sphinx או תוסף יכולים להתנהג שם אחרת. אם RTD אדום ולוקאלית ירוק — RTD צודק, כי הוא הסביבה שמפרסמת.

  • החריג: עמוד חדש, או נגיעה ב-``toctree``/``conf.py``. שם טעות מפילה את הבילד כמעט בוודאות (document isn't included in any toctree), והבדיקה זולה כי אפשר לבנות עמוד בודד: python -m sphinx -b html -W . _build/html <עמוד>.rst.

  • השתמשו ב‑copybutton לקוד שמיועד ל‑Copy‑Paste.

  • שמרו עוגנים יציבים לכותרות עיקריות.

קישורים