# סיכום סשן — 0034
תאריך: 2026-05-30 21:52
אפליקציה: Vitruvius
נושא: M7 — UpdateChecker

## מה נבנה/הושלם

### M7 — UpdateChecker (סגור ✓)
פלאגין Revit בודק עכשיו בעלייה אם יצאה גרסה חדשה דרך בקשת HTTPS אחת לקובץ manifest, ואם כן — מציג TaskDialog עם 3 כפתורים (פתח דף הורדה / דלג על גרסה זו / תזכיר בפעם הבאה).

**4 קבצים חדשים:**
1. `src/Vitruvius.Core/Updates/UpdateInfo.cs` — DTO + `UpdateCheckResult` (never throws; שגיאות נכנסות לשדה Error)
2. `src/Vitruvius.Core/Updates/SemVer.cs` — השוואת 3 חלקים + pre-release tail. הכלל: "כל suffix" sorts לפני "ללא suffix" (`0.2.0-beta < 0.2.0`)
3. `src/Vitruvius.Core/Updates/UpdateChecker.cs` — HTTP GET, HTTPS-only, TLS 1.2 explicit (`ServicePointManager.SecurityProtocol |= Tls12`), timeout 10s, 16KB cap על body, parser JSON inline (אותו דפוס כמו VitruviusConfig — בלי Newtonsoft/STJ). מאמת ש-`downloadUrl` ב-manifest הוא גם HTTPS.
4. `src/Vitruvius.Revit2024/Updater/UpdateNotifier.cs` — `Start(UIControlledApplication)` נקרא ב-OnStartup: מנוי ל-Idling + `Task.Run` ברקע שמריץ את הבדיקה. ב-Idling הראשון אחרי שהבדיקה החזירה תוצאה, מציג TaskDialog ב-Revit API thread, מנקה את המנוי. Anti-nag: `_shown` bool למניעת popup חוזר באותו סשן + `SkippedUpdateVersion` ב-config למניעת popup על אותה גרסה לעולם.

**4 קבצים שונו:**
1. `src/Vitruvius.Core/VitruviusInfo.cs` — `DefaultUpdateManifestUrl = "https://vitruvius.app/updates/manifest.json"` (placeholder, ראה caveat #1)
2. `src/Vitruvius.Core/State/VitruviusConfig.cs` — 3 שדות חדשים: `UpdateCheckEnabled` (default **true**), `UpdateManifestUrlOverride` (default null), `SkippedUpdateVersion` (default null). Load+Serialize עודכנו. SchemaVersion נשאר 1 (backward-compat: שדות חסרים → defaults).
3. `src/Vitruvius.Revit2024/VitruviusApp.cs` — `_updateNotifier = new UpdateNotifier(); _updateNotifier.Start(application);` ב-OnStartup, עטוף ב-try/catch (כשל ב-init לא יפיל את הריבון). ב-OnShutdown: `_updateNotifier.Stop()` שמבטל את ה-CancellationToken ואת ה-Idling subscription.
4. `src/Vitruvius.Revit2024/UI/SettingsWindow.cs` — סקציה חדשה "עדכונים" אחרי "תמיכה ב-DWG": Toggle (`UpdateCheckEnabled`), טקסט גרסה נוכחית, כפתור "בדוק עכשיו" אסינכרוני (`async (_, _) => await UpdateChecker.CheckAsync(...)`), כפתור "פתח את דף ההורדה" שמופיע רק אם יש update, ו-"בטל דילוג" שמופיע רק אם `SkippedUpdateVersion` קיים.

### Build & Deploy
- MSBuild על `Vitruvius.slnx` — `Restore,Build -p:Configuration=Debug` נקי, אפס warnings.
- Core 66KB→78KB · Revit2024 79KB→89KB.
- Deployed `C:\ProgramData\Autodesk\Revit\Addins\2024\Vitruvius\`.
- ארכוב OLD\2026-05-30_12-02\ לפי כלל הארכוב הגלובלי.

### PLAN.md
שורת M7 מסומנת ✓ עם תיאור מלא של מה שנבנה בפועל (לא רק "done").

### HTML סיכום RTL לנייד
נוצר `D:\Vitruvius Ecosystem\Vitruvius\_M7-update-checker-summary.html` — 6 בלוקים, Rubik 19px, ניגוד גבוה. ניסיון להגיש דרך Python HTTP server מקומי על port 8090 נכשל — Windows Firewall חוסם python.exe ב-Public profile (2 כללי Block פעילים). הצעתי 3 פתרונות (Set Network Private / Disable Block rules / לקבל את הפדפן הדיפולטי במחשב); המשתמש דחה ואמר "לא משנה". השרת נסגר.

## החלטות שהתקבלו

1. **URL דיפולטי = placeholder, לא חי.** `https://vitruvius.app/updates/manifest.json` לא קיים. עד שיהיה release pipeline (M9 installer), הבדיקה נכשלת בשקט — זה ה-design. בלי nag, רק שורה ב-`%APPDATA%\Vitruvius\diagnostic.log`. לבדיקה end-to-end: להעלות JSON ל-GitHub Raw ולהכניס את ה-URL לשדה `updateManifestUrlOverride` ב-`%APPDATA%\Vitruvius\config.json`.

2. **"הורדה" פותחת דפדפן, לא in-process.** הטעמה: installer עוד לא קיים (M9). כפתור "פתח את דף ההורדה" קורא `Process.Start(new ProcessStartInfo(url) { UseShellExecute = true })` ופותח את ה-URL בדפדפן הדיפולטי. אם installer יהיה in-process בעתיד, ה-DownloadUrl פשוט יצביע ל-`.exe` והדפדפן יוריד.

3. **Anti-nag דו-שכבתי:** (א) `_shown` bool ב-UpdateNotifier — TaskDialog מופיע פעם אחת לכל הסשן, גם אם המשתמש סוגר אותו ועושה משהו אחר. (ב) `SkippedUpdateVersion` ב-config — אם המשתמש לחץ "דלג על גרסה זו", לא נציג שוב את הדיאלוג עבור אותה מחרוזת `latestVersion`. גרסה חדשה יותר ב-manifest (string compare !=) תקפוץ כרגיל.

4. **HTTPS-only כפול:** גם ה-manifest URL חייב להיות HTTPS (נדחה pre-flight ב-UpdateChecker), וגם `downloadUrl` בתוך ה-manifest. אם downloadUrl לא-HTTPS — הפרסר מחזיר null ומתעדכנת שורה ב-log. הנמקה: אם ה-installer מועבר בערוץ פלייntext, MITM יכול להחליף את ה-payload.

5. **TLS 1.2 explicit.** net48 default-ים ל-TLS 1.0 בהרבה מארחים (Revit לא קונפיגר אחרת). `ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls12` ב-static constructor של HttpClient.

6. **16KB cap על response body.** Manifest = JSON זעיר. אם משהו מחזיר HTML או payload גדול — נחתוך ב-16KB ונשבור parse בשקט.

7. **Idling pattern לא Dispatcher.** Background HTTP → `_result` field → `Idling` event → UI thread → TaskDialog. הסיבה: Revit single-threaded על API thread; אסור להציג UI מ-Task. Dispatcher.BeginInvoke לא מספיק כי לא ה-WPF dispatcher הוא ה-Revit API thread. Idling זה ה-canonical pattern של Revit.

8. **Schema version של config לא הוקפץ.** Load סלחני (שדות חסרים → defaults), אז backward compat שמור. הוספת שדות תמיד additive-safe.

## בעיות שנפתרו

### Python HTTP server לא נגיש מהנייד
**הבעיה:** המשתמש קיבל ERR_CONNECTION_TIMED_OUT בנייד גם כשהיו על אותה רשת.
**אבחון:** `Get-NetFirewallRule -DisplayName "*python*"` חשף 2 כללי Block פעילים על python.exe ב-Public profile. `Get-NetConnectionProfile` חשף שהכרטיס Ethernet מסומן Public.
**הצעות לפתרון:** (א) `Set-NetConnectionProfile -InterfaceAlias Ethernet -NetworkCategory Private` — הכי נקי, התואם למצב של רשת ביתית/משרדית; (ב) `Disable-NetFirewallRule` על 2 הכללים; (ג) לקבל את ה-HTML רק בדפדפן ה-PC.
**הכרעה:** המשתמש דחה ואמר "לא משנה". השרת נסגר עם `Stop-Process`.

## מה לא עבד / צריך להיזהר

- **ServicePointManager.SecurityProtocol — bitwise OR.** השתמשתי ב-`|=` (לא `=`) כדי לא לדרוס פרוטוקולים שהאפליקציה כבר תמכה בהם.
- **Stop-Process -Force לא תמיד מספיק.** ה-Python process עדיין הופיע ב-PID 36492 אחרי `Stop-Process`. עברתי ל-`taskkill /PID 36492 /F`. הפעם ההודעה הייתה "process not found" כי Stop-Process הצליח רק נדמה שלא — בעצם הוא כבר נסגר. צריך לפעמים Start-Sleep 500ms בין הפעולות.
- **כל קריאה ל-Network ב-OnStartup חייבת להיות wrapped ב-Task.Run.** אסור לחסום את ה-startup על HttpClient.GetAsync — משתמש על Wi-Fi איטי או מאחורי captive portal יקבל Revit קפוא ל-30 שניות. ה-task נופל לתוך thread pool ומ-await-מ-end ב-result field שה-Idling יקרא.
- **AccoreConsole serialize trailing comma.** ב-VitruviusConfig.Serialize() החדש, צריך לוודא שאחרון השדות אין לו פסיק. אחרי 3 שדות חדשים שינתי את הסיומת של accoreConsolePathOverride מ-"\n" ל-",\n" (כי עכשיו אחריו יש שדות). חשוב לעקוב על זה בכל הרחבה עתידית.
- **net48 + System.Net.Http.** ה-HttpClient זמין directly ב-net48 ו-netstandard2.0; לא הוספתי PackageReference. תוצאות חיוביות.

## קבצים שנוצרו/שונו

### נוצרו
- `D:\Vitruvius Ecosystem\Vitruvius\src\Vitruvius.Core\Updates\UpdateInfo.cs`
- `D:\Vitruvius Ecosystem\Vitruvius\src\Vitruvius.Core\Updates\SemVer.cs`
- `D:\Vitruvius Ecosystem\Vitruvius\src\Vitruvius.Core\Updates\UpdateChecker.cs`
- `D:\Vitruvius Ecosystem\Vitruvius\src\Vitruvius.Revit2024\Updater\UpdateNotifier.cs`
- `D:\Vitruvius Ecosystem\Vitruvius\_M7-update-checker-summary.html` (סיכום RTL לנייד)

### שונו
- `D:\Vitruvius Ecosystem\Vitruvius\src\Vitruvius.Core\VitruviusInfo.cs` (+DefaultUpdateManifestUrl)
- `D:\Vitruvius Ecosystem\Vitruvius\src\Vitruvius.Core\State\VitruviusConfig.cs` (+3 שדות, Load+Serialize)
- `D:\Vitruvius Ecosystem\Vitruvius\src\Vitruvius.Revit2024\VitruviusApp.cs` (wired UpdateNotifier)
- `D:\Vitruvius Ecosystem\Vitruvius\src\Vitruvius.Revit2024\UI\SettingsWindow.cs` (+סקציית עדכונים)
- `D:\Vitruvius Ecosystem\Vitruvius\PLAN.md` (M7 ✓)

### Deployed
- `C:\ProgramData\Autodesk\Revit\Addins\2024\Vitruvius\Vitruvius.Core.dll` (78KB)
- `C:\ProgramData\Autodesk\Revit\Addins\2024\Vitruvius\Vitruvius.Revit2024.dll` (89KB)
- ארכוב: `OLD\2026-05-30_12-02\` (4 קבצים)

## הצעד הבא

**M8 — LicenseManager stub** (אומדן יום).

מטרה: תשתית מוכנה לחיבור תשלום עתידי (Lemon Squeezy + iCount), בלי לבנות עדיין שום דבר אמיתי. ה-stub `IsActivated() → true` תמיד, אבל ה-call sites נכנסים עכשיו לכל IExternalCommand כך שכשהמימוש האמיתי ייכנס ב-Phase 2 — אין שום שינוי בקוד הפלאגין.

צעדים מוצעים:
1. ליצור `D:\Vitruvius Ecosystem\Vitruvius\src\Vitruvius.Core\Licensing\LicenseManager.cs` עם:
   - static class
   - `public static bool IsActivated() => true;` (stub)
   - `public static string TierName => "MVP";` (placeholder ל-UI)
   - חתימת method `void RequireActivated(string commandName)` שזורק `LicenseRequiredException` אם false (לעתיד)
2. ליצור `D:\Vitruvius Ecosystem\Vitruvius\src\Vitruvius.Revit2024\Licensing\LicenseGuard.cs` עם:
   - `static bool Ensure(ExternalCommandData commandData)` שמחזיר false ומציג TaskDialog ידידותי אם לא activated
3. לעטוף את 5 ה-Commands:
   - `FixGibberishCommand` · `RestoreToOriginalCommand` · `SettingsCommand` · `AboutCommand` · `LayerEditCommand`
   - בכל אחד: `if (!LicenseGuard.Ensure(commandData)) return Result.Cancelled;` בתחילת `Execute`
4. About dialog להראות "מסלול: MVP" (קריאה ל-`LicenseManager.TierName`)
5. Build + Deploy + ארכוב לפי הכלל הגלובלי
6. PLAN.md — M8 ✓
7. סגירת סשן

**אופציה לחילופין:** לבדוק את M7 end-to-end עם manifest אמיתי על GitHub Raw לפני שנעבור ל-M8. המשתמש לא ביקש את זה במפורש, אבל זה ה-validation היחיד שלא הריצוצי בסשן הזה.
