בפוסט הקודם כתבתי ש"הזיכרון הוא הנכס, לא הסוכנים", ואז המשכתי הלאה בלי להראות אף שורה ממנו. אז הנה שורה אחת, והנה הבאג שבגללו שכתבתי את כל הפרוטוקול.
Image by TheDigitalArtist from Pixabay
נתחיל בשורה עצמה. היא עוסקת בהתנהגות של סינון (filter) במסד הנתונים שלנו — מונגו (MongoDB) — והיא אומרת בערך כך: כשמוסיפים שדה חדש למודל, כל המסמכים שנוצרו לפני כן פשוט לא מכילים אותו, וסינון לפי ערך לעולם לא ימצא אותם. לא "לא שווה אמת", לא "שונה מ־אמת", לא שום ניסוח אחר. אפס תוצאות. הדרך היחידה למצוא אותם היא לשאול אם השדה קיים בכלל.
זה משעמם. זה גם עלה לנו, בשתי הזדמנויות נפרדות, בסעיף שלם באפליקציה שהציג רשימה ריקה בשקט.
הרפלקס הטבעי הוא "אז תכתבו את זה בתיעוד". ניסיתי. תיעוד הוא מקום שבו כותבים דברים כדי להרגיש טוב, לא כדי לקרוא אותם.
מה שכן עובד צר בהרבה: בסוף כל משימה, כל סוכן כותב לעצמו רשומת לקחים — לא תיאור של מה שעשה, אלא מה שלמד — והרשומה נטענת אליו אוטומטית בפעם הבאה שהוא מתעורר. הוא לא מחפש אותה. היא כבר שם.
רשומה אמיתית מהריפו, בדיוק כפי שהיא נשמרה. שימו לב למשפט האחרון — הוא הסיבה שהקובץ קיים. בלעדיו מישהו יחקור בדיוק את אותו כיוון בעוד חודשיים, יגיע לאותה מסקנה, וישלם עליה שוב.
| מדד | כמותנכון ל־13.8.2026 |
|---|---|
| רשומות יומן שנכתבו מאז 2 ביולי | 256 |
| קבצי נושא מזוקקים | 109 |
| שורות של זיכרון מתוחזק | 1,019 |
| תיקים אישיים | 13 |
| תקרה לתיק זיכרון ראשי | ~200 שורות |
ספירה ישירה מהריפוזיטורי. "רשומת יומן" = קובץ לקחים בודד שנכתב בסוף משימה; "קובץ נושא" = מה שנשאר אחרי הזיקוק. היחס בין השניים הוא לא בזבוז — הוא כל העבודה.
הכלל שמחזיק את כל זה הוא כלל התקציב: תיק הזיכרון הראשי של כל סוכן מוגבל לכ־200 שורות. לא בגלל אילוץ טכני, אלא כי בלי תקרה זיכרון הופך לערימה, וערימה זה בדיוק אותו כלום כמו תיעוד.
והתקרה הזאת היא גם מקור כל הצרות. מיד אסביר למה.
תקציב קשיח אומר שהזיכרון לא נכתב בהוספה (append). הוא נכתב בכתיבה מחדש: שורות מתמזגות, מתקצרות, זזות ממקום למקום.
עכשיו הוסיפו לזה שאני מריץ שלוש עד חמש עבודות במקביל, כל אחת בעותק עבודה נפרד של הקוד (git worktree) ועל ענף משלה (branch). שתי עבודות שונות שמזקקות את אותו קובץ זיכרון לא מייצרות התנגשות מיזוג (merge conflict) שגיט יודע לפתור — הן מייצרות התנגשות של משמעות. שתי הגרסאות תקינות תחבירית. שתיהן נראות סבירות. ומי שמיישב ביניהן בוחר, בלי לדעת, איזו עובדה שורדת.
אלא שהכישלון שבאמת קרה היה גרוע מזה, כי הוא לא הצריך התנגשות בכלל. השורה השגויה על מסד הנתונים לא נכתבה לתיק אחד. היא נכתבה ביום הראשון, באותו קומיט מייסד, לשישה תיקים במקביל. וכשמתקנים עובדה כזאת, מתקנים אותה במקום אחד.
שניים מהסוכנים קיבלו את התיקון ב־25 ביולי, בשתי בקשות משיכה נפרדות שנחתו במקרה באותו יום. ארבעת האחרים המשיכו להתעורר עם הגרסה השגויה עוד שמונה־עשר יום, עד שמעבר הזיקוק ניקה אותה מכולם בבת אחת.
הזיכרון לא רק נכשל במניעת באג. הוא החזיר לחיים באג שכבר שילמנו עליו וקברנו
ובאותו 25 ביולי, על אותו קובץ עצמו, קיבלתי גם את הכשל השני — זה שלקח לי עשר דקות לזהות: בקשת משיכה (Pull Request) שלא רצות עליה בדיקות בכלל. לא נכשלות — לא קיימות. נראה בדיוק כמו תקלה בשירות הבדיקות (CI).
כשיש התנגשות, אין מה לבנות. שאלה אחת בשורת הפקודה הייתה חושפת את זה מיד. אני חיפשתי במקום אחר.
זיכרון לא שייך לעותק המבודד של הסוכן.
בסוף משימה, סוכן לא עורך את קובץ הזיכרון. הוא כותב קובץ חדש ביומן (journal), עם תאריך ונושא, ישירות בעותק הראשי (main checkout) — ולא בעותק העבודה שלו. קבצים חדשים לא יכולים להתנגש זה בזה; זו כל התוכנית. אחת לתקופה רץ מעבר זיקוק אחד, בעל כותב יחיד, שמקפל את היומן לתוך קבצי הנושא ומחזיר אותם מתחת לתקציב.
בלי לתכנן את זה מראש, הפרדתי כתיבה מקריאה: היומן הוא תוסף־בלבד (append-only), קבצי הנושא הם נתיב הקריאה המהיר. מפתחים יזהו את התבנית. אני גיליתי אותה מחדש בדרך הקשה, אחרי שהפסדתי בדיוק עובדה אחת.
והיום זה נאכף, לא מבוקש:
כל אחד מהתאריכים האלה הוא כלל שנוסף אחרי כישלון, בדיוק בסדר הזה. אף אחד מהם לא נכתב מראש.
התוכן ברשומות הוא לא ידע. ידע יש לסוכנים בשפע, ואת רובו הם יודעים טוב ממני.
מה שיש שם זה ידע מקומי (local knowledge): ששרתי הייצור אצלנו נושאים שם שנשמע כמו סביבת פיתוח, ואסור להסיק מהשם כלום. שמדד זמן מסוים בלוגים שלנו לא מודד את מה שכתוב בשמו. שתהליך רקע מסוים עלול, בכיבוי לא מסודר, להשתיק את כל מיילי ההתראות של המערכת בלי שאף אחד ישים לב.
זה בדיוק הידע שעובד חדש לא יכול להביא איתו, ושעובד ותיק לוקח איתו כשהוא עוזב. ההבדל היחיד הוא שאצלי הוא בגיט, ואפשר לראות מתי הוא נכתב ועל חשבון איזה באג.
שורת זיכרון היא באג ששילמנו עליו פעם אחת. בלי זיכרון משלמים עליו כל שבוע מחדש. עם זיכרון שאי אפשר לתקן — משלמים עליו לנצח
והחלק האחרון הוא החשוב מכולם, ולקח לי חודש להבין אותו. זיכרון ארגוני הוא לא מאגר שצוברים אליו. הוא מאגר שצריך גם למחוק ממנו. עובדה ישנה שנשארת בפנים מסוכנת יותר מעובדה חסרה, כי סוכן לא יטרח לאמת מה שכתוב אצלו בתיק.