|
1 | | -# Handoff — Windows COM-backend verification (`feat/com-backend`) |
| 1 | +# Handoff — Windows COM-backend verification |
2 | 2 |
|
3 | | -**Date:** 2026-05-29 · **Branch:** `feat/com-backend` · **Host:** Windows 11 on **ARM64**, App Installer `Microsoft.DesktopAppInstaller 1.29.140.0` (Arm64), winget `v1.29.140-preview`. |
| 3 | +**Latest:** session 3 · 2026-06-13 · branch `main` · Windows 11 **ARM64**, App Installer `1.29.250.0` (Arm64), winget `v1.29.250`. |
| 4 | +**Originally:** session 2 · 2026-05-29 · branch `feat/com-backend` · App Installer `1.29.140.0`, winget `v1.29.140-preview`. |
4 | 5 |
|
5 | | -This was a human-in-the-loop Windows verification run against `WINDOWS-TESTING.md`. A human drove the |
6 | | -interactive TUI; the agent handled builds, non-interactive checks, diagnosis, and fixes. |
| 6 | +Sessions 1–2 were human-in-the-loop (a human drove the interactive TUI; the agent handled builds, |
| 7 | +non-interactive checks, diagnosis, fixes). Session 3 was fully autonomous (no human at the TUI), so it |
| 8 | +resolved the headline question and exercised the COM backend via read-only diagnostics rather than the |
| 9 | +interactive flows — see the session-3 block immediately below. |
| 10 | + |
| 11 | +--- |
| 12 | + |
| 13 | +## ✅ SESSION 3 (2026-06-13) — headline question RESOLVED + a second COM bug found & fixed |
| 14 | + |
| 15 | +**1. The COM-on-AOT activation question is settled: it is a genuine Native-AOT bug. Ship the COM build non-AOT.** |
| 16 | +On a freshly-booted host (boot 6:02 PM; WinGet COM server healthy & long-lived since 6:04 PM) with an |
| 17 | +*updated* App Installer (1.29.250, was 1.29.140), `--comdiag` was run as the first deliberate COM probe: |
| 18 | + |
| 19 | +| Build | `coreclr.dll` | `--comdiag` (main + threadpool, both MTA) | |
| 20 | +|-------|---------------|-------------------------------------------| |
| 21 | +| **Native AOT** (fresh publish) | absent | **FAILED `0x80073D54`** — reproduced 3× (stale 5/30 binary, fresh build, final build with the fix) | |
| 22 | +| **JIT self-contained x64** (same source) | present | **OK — 3 catalogs** | |
| 23 | + |
| 24 | +Same source, same projection (`ComInterop 1.29.190-preview`), same machine, same minute. This closes the |
| 25 | +session-2 "open contradiction": the failure is **deterministic and AOT-specific**, not transient |
| 26 | +COM-server/AppModel state. The early session-1 AOT-spike "success" was the anomaly. |
| 27 | + |
| 28 | +**Root cause (grounded in upstream):** the WinGet projection `Microsoft.Management.Deployment.CsWinRTProjection.dll` |
| 29 | +is precompiled against an old CsWinRT. Under JIT the runtime activation factory still activates the |
| 30 | +registered OOP server; under AOT (no reflection fallback) activation falls through to the identity-requiring |
| 31 | +path → `APPMODEL_ERROR_NO_PACKAGE`. The manual-activation shim `winrtact.dll` |
| 32 | +(`WinGetServerManualActivation_CreateInstance`) was **dropped from ComInterop ≥ 1.10.x** |
| 33 | +([winget-cli#5459](https://github.com/microsoft/winget-cli/issues/5459)) and is absent from our package |
| 34 | +(confirmed — not in the nupkg or publish dir); upstream [#4839](https://github.com/microsoft/winget-cli/issues/4839) |
| 35 | +requests an AOT-capable projection.dll, not yet shipped. |
| 36 | + |
| 37 | +**Leads investigated:** |
| 38 | +- **CsWinRT 3.x → NOT viable.** `Microsoft.Windows.CsWinRT 3.0.0-preview.260319.2` breaks the build at its own |
| 39 | + `cswinrt.exe` codegen step (`Path '…\microsoft.windows.sdk.net.ref\…\winmd\windows\' is not a file or directory`) |
| 40 | + and would conflict with the projection's bundled WinRT.Runtime anyway. Reverted. |
| 41 | +- **Did NOT retry** (banner "did not fix it"): CsWinRT 2.2.0 optimizer, the Win10 `app.manifest`, server warming. |
| 42 | +- **InProcCom (`Microsoft.WindowsPackageManager.InProcCom`, ~100 MB in-proc server) → untried.** The only |
| 43 | + remaining AOT-keeping lead; would also erase most of AOT's size win. |
| 44 | + |
| 45 | +**RECOMMENDATION:** ship the **Windows/COM build non-AOT** (JIT self-contained — confirmed to activate COM |
| 46 | +and return full data). **Size cost: 22.4 MB AOT single-exe → 112.7 MB JIT self-contained folder (~5×).** |
| 47 | +Alternatively keep AOT and accept the CLI backend on Windows (loses Verify/Repair/preview/version-picker/progress). |
| 48 | + |
| 49 | +**2. 🐛 Second, independent COM bug FOUND & FIXED — `ComBackend.ConnectAsync` (`src/ComBackend.cs`).** |
| 50 | +`ConnectAsync` set `reference.AcceptSourceAgreements = true` on the **composite** catalog reference, which |
| 51 | +throws `E_ILLEGAL_STATE_CHANGE` (`set_AcceptSourceAgreements` on `IPackageCatalogReference3`). All three |
| 52 | +composite-connect callers (search, list, find-by-id) hit it — so **every COM search/list/detail would have |
| 53 | +thrown the instant COM activated.** It stayed latent because AOT always fell back to CLI, so the COM path |
| 54 | +never actually ran in the app. `RemoteRefs` already sets `AcceptSourceAgreements = true` on each *source* |
| 55 | +ref (the API-correct place) before compositing, making the composite set both redundant and illegal. |
| 56 | +**Fix:** removed the set from `ConnectAsync` (comment explains why). After the fix, the full COM surface works. |
| 57 | + |
| 58 | +**3. COM verification done on the JIT build (read-only, non-destructive) — all passing:** |
| 59 | +- Badge / `DescribeAsync` → **`COM · winget 1.29.250`** · `CanRepair` → **True** |
| 60 | +- `ListSourcesAsync` → **`msstore, winget, winget-font`** (dynamic; picks up the custom `winget-font` source) |
| 61 | +- `SearchAsync("powertoys")` → **19** results (`PowerToys [Microsoft.PowerToys] 0.100.0 winget`) |
| 62 | +- `ListInstalledAsync` → **299** · `ListUpgradesAsync` → **10** (`PostgreSQL 18 18.3-3 → 18.4-1`, Available populated) |
| 63 | +- `ListVersionsAsync(Microsoft.PowerToys)` → **112** versions, newest-first |
| 64 | +- `GetInstallerPreviewAsync(Microsoft.PowerToys)` → **`Burn · arm64 · user`** |
| 65 | +- `VerifyInstalledAsync(ajeetdsouza.zoxide)` → **Issues**, `1 of 3 checks failed` (`Registry entry — hr 0x8A150201`) |
| 66 | +- `ShowAsync(Microsoft.PowerToys)` → **Tags (10), Support, Documentation(Wiki), Author, Copyright, Privacy** all |
| 67 | + populate → **resolves the old `#17`** (ProductCode/FamilyName null is legit — PowerToys is a `burn` installer). |
| 68 | +- **Operation + progress paths** (`--comop ajeetdsouza.zoxide`, on COM/JIT — these had NEVER run before): |
| 69 | + - `DownloadAsync(zoxide)` → **Success**, files actually landed in `%USERPROFILE%\Downloads\winget-tui` |
| 70 | + (`zoxide_0.9.9_Arm64_portable_en-US.zip` 480 KB + `.yaml`; COM resolved the **arm64** installer). The |
| 71 | + `IProgress<OpProgress>` callback fired (phase **Downloading**, fraction → 1.00) — **the "live progress" |
| 72 | + marshaling works on COM** (the old "CCW under AOT" unknown is moot: COM doesn't run under AOT). Cleaned up. |
| 73 | + - `RepairAsync(zoxide)` → **Success=False**, `Repair failed: RepairError (repairer 0, hr 0x8A15007C)`, |
| 74 | + **no crash** — zoxide is a portable .zip with no repairer. NB this is the `RepairError` path, *distinct* |
| 75 | + from `NoApplicableRepairer`; the message leaks the raw HRESULT. Possible follow-up: map portable/no-repairer |
| 76 | + to the friendly "doesn't support repair." line. The `Verify(Issues) → Repair → Verify` sequence ran e2e. |
| 77 | +- `dotnet test -f net10.0` → **pass** (18 facts incl. all three P1.5 ports' logic). |
| 78 | + |
| 79 | +**4. Still NOT verified (need a human at the interactive TUI, and/or are destructive):** actual |
| 80 | +install/uninstall/upgrade *execution* (download + repair WERE exercised — see item 3); the **status-bar progress |
| 81 | +render** + cooperative **Esc cancel**; the dialog/panel *rendering* (install preview, version-picker list, |
| 82 | +advanced-install options, Verify→Repair-button flow); the three P1.5 ports' end-to-end terminal *interaction* |
| 83 | +(mouse header clicks, `u`/`P`/`/` keypresses); pinning; the P2 thread-agility / unhealthy-source probes. |
| 84 | +NOTE: the "live progress under **AOT**" CCW-marshaling item is **moot** — COM doesn't run under AOT; under JIT |
| 85 | +(the COM ship vehicle) the callback path is standard and was confirmed via `DownloadAsync`. |
| 86 | + |
| 87 | +**5. Fixes committed (session 3).** Beyond the `ConnectAsync` COM-activation fix, this pass found and fixed, |
| 88 | +from a real interactive COM run + the user's feedback: |
| 89 | +- **Verify false "Issues"** (`src/ComBackend.cs` `VerifyInstalledAsync`): `CheckInstalledStatus` returns a block |
| 90 | + per *manifest installer*; the non-installed ones report "ARP entry not found" (0x8A150201). Old code flattened |
| 91 | + all installers and flagged Issues on any failure → healthy multi-installer/portable packages looked corrupt. |
| 92 | + Now grouped per installer: **Ok if any one installer's checks all pass**; the dialog shows that clean installer. |
| 93 | +- **Narrow-terminal columns** (`src/App.cs`): Name/Id/Version shrink toward minimums so **Available** stays |
| 94 | + visible instead of being pushed off-screen; reflows on resize via `ViewportChanged`. |
| 95 | +- **Installed-in-Search** (`src/ComBackend.cs` `SearchAsync`, `DetailPanel.cs`, `Models.cs`): search rows read the |
| 96 | + composite's correlated `InstalledVersion`; an installed row shows a **✓ Installed** badge and Uninstall/Upgrade |
| 97 | + actions instead of a bare Install. |
| 98 | +- **Op result through reload** (`src/App.cs` `TriggerRefresh`): the result line ("Done"/…) persists through the |
| 99 | + post-op list reload instead of being masked by "Loading Installed…". |
| 100 | +- **Bulk-select hint** (`src/Ui.cs`): the Upgrades status bar shows `Spc Select` / `U Upgrade sel`. |
| 101 | + |
| 102 | +The temp `#if WINGET_COM` diagnostics (`--comdiag`/`--comshow`/`--comsmoke`/`--comverify`/`--comop`) were |
| 103 | +**removed before commit** (re-add `--comdiag` from the appendix for the AOT activation work). Test dir |
| 104 | +`bin\jit-x64-test\` and `bin\…\publish\` are build outputs (gitignored). |
| 105 | + |
| 106 | +--- |
| 107 | + |
| 108 | +## (Session 2, 2026-05-29) original headline finding — superseded by session 3 above, kept for history |
7 | 109 |
|
8 | 110 | > **⚠️ If you are running on WSL / Linux:** you **cannot** run the Windows verification here. |
9 | 111 | > Native AOT codegen can't cross-compile from Linux, and the WinGet COM server + installs need |
|
0 commit comments