#1 今天 17:15:04
AI 兩大名醫聯手救電腦|卡在 98% 的真相
我們有一台 Windows 11 筆電,從九月底開始,每次累積更新都在重新開機後卡在 88%~98%,接著出現「正在復原變更」,一切回到原點。關機選單裡也沒有「關機」,只剩「更新並關機」和「更新並重新啟動」,不更新不能關機,更新又裝不起來。
這次除錯我們同時找了兩個 AI 助手:Claude 和 Codex。兩邊都提出過診斷,也都講錯過。後來我們讓兩邊在同一份筆記上互相檢查,才在 11 月 6 日把問題找出來:系統裡一個應用程式資料庫,83,042 筆記錄中有 1 筆損毀,擋住了更新。
這篇記錄整個過程,包括走過的彎路、用到的指令,以及這個結論的界線在哪裡。
■ 先講結論
---
◆ 01 症狀與環境
| 項目 | 內容 |
|---|---|
| 系統 | Windows 11 家用版 25H2(26200.8457) |
| 症狀 | 累積更新重新開機後卡在 88%~98%,接著回滾 |
| Windows Update 錯誤碼 | 0x800f0922(9 月、11/4)、0x800f0920(11/6) |
| CBS 記錄的錯誤 | AppX Registration Installer,HRESULT 80670015 |
| 試過但沒用 | DISM RestoreHealth、SFC、修復重新安裝、官方 ISO、安裝小幫手 |
| 附帶狀況 | 曾經藍屏 MEMORY_MANAGEMENT;C 槽有 BitLocker 加密;WinRE 停用 |

---
◆ 02 走過的彎路
1. 記憶體
這台筆電藍屏過,錯誤是 MEMORY_MANAGEMENT。Windows 記憶體診斷的結果是:兩條記憶體都裝著時報錯,只留主機板上的 8 GB 時通過。Claude 當時判斷是後來加裝的 16 GB 有問題。
拔掉 16 GB 再更新,照樣失敗(0x800f0922)。記憶體可能真的不穩,但不能證明它就是更新失敗的原因。這條 16 GB 目前仍未裝回。

2. 修復重新安裝
9 月 30 日我們做了修復重新安裝(保留檔案和應用程式),在 99% 停了很久才裝完。裝完 Windows Update 顯示「您現在為最新狀態」,但一按「檢查更新」,跳出來的累積更新和 .NET 更新又一起失敗,錯誤碼還是 0x800f0922。
這時 CBS 記錄已經指出失敗點是 AppX Registration Installer(錯誤 80670015),但 AppX 的服務、事件記錄、Get-AppxPackage -AllUsers 看起來都正常,線索就斷在這裡。

3. 官方 ISO 與安裝小幫手
想用就地升級的方式重鋪一次,結果安裝程式在相容性檢查階段就擋下來(HostIsNewer → HardBlock,錯誤 0xC1900205-0x4000B),只剩「全新安裝」可選。為什麼被擋,到現在還不知道;這次沒有處理。
4. 「磁碟 2 讀寫錯誤」
事件記錄裡有磁碟 2 的讀寫錯誤,一度懷疑是硬碟。查了才知道磁碟 2 是一支約 4 GB 的 USB 隨身碟,和這件事無關。
---
◆ 03 關鍵線索:失敗那一秒的事件記錄
CBS 記錄只告訴我們「AppX 註冊失敗」,沒說為什麼。真正的線索在另一份事件記錄:StateRepository。StateRepository 是 Windows 記錄「每個應用程式裝在哪、有哪些檔案」的資料庫服務,AppX 註冊時要寫入它。
11 月 4 日那次失敗,CBS 記錄的錯誤時間是 15:41:28:
2026-11-04 15:41:28, Error CSI ... appxreg.cpp(218): Error 80670015 ...
originated in function ...AppxRegistrationInstaller::CommitChanges
expression: RDSAppXOnlineNotifyPackageChanges(APPCHANGETYPE_INBOX)
... Failure will not be ignored: A rollback will be initiated ...
同一秒,StateRepository 的事件記錄寫著:
database disk image is malformed
11 月 6 日早上 07:08 又失敗一次,事件記錄更完整:
Id 227:錯誤 0x87AF000B: StateRepository 服務無法啟動 [檢查點=800]
Id 107:CriticalError 0xB: statement aborts at 13: database disk image is malformed;
[INSERT INTO main.File (_FileID, _Revision, ...) SELECT s._FileID, ... FROM Source.File AS s;]
Id 107:CriticalError 0xB: database corruption at line 98572 of [737ae4a347]
查詢指令(系統管理員 PowerShell,唯讀):
Get-WinEvent -FilterHashtable @{
LogName = 'Microsoft-Windows-StateRepository/Operational'
Id = 107, 227
StartTime = (Get-Date).AddDays(-3)
} | Format-List TimeCreated, Id, Message
CBS 記錄在 C:\Windows\Logs\CBS\CBS.log,可以用 findstr 80670015 找失敗那一行,再拿它的時間去對 StateRepository 的事件。
如果你的更新也是 0x800f0922 加上 AppX Registration Installer 80670015,建議先查這份事件記錄。
---
◆ 04 讓兩個 AI 共用一份筆記
前面幾輪,我們是把一邊的結論複製給另一邊看,再把回覆貼回來。傳了幾輪之後,我們乾脆建了一個資料夾,放一份 notes.md,讓兩邊直接在上面討論,規則是:
效果很明顯。Claude 講錯並撤回的有好幾條,例如:把 HostIsNewer 比對的版本號說成「系統殘留的較新元件」(Codex 指出那是安裝程式自己的版本)、低估了用 SQLite .recover 搶救後覆蓋正式資料庫的風險、把失敗時間點說成「搬資料時」(Codex 用 CBS 記錄指出是更新收尾、註冊應用程式時)。Codex 則負責把每個修復提案的範圍收窄,下一節的操作條件大多是它加的。
兩邊最後的共識是:先不修,先拿到一份資料庫複本,在複本上找出到底哪裡壞了。

---
◆ 05 複製資料庫:WinRE 被 BitLocker 擋住,改用陰影複製
資料庫在 C:\ProgramData\Microsoft\Windows\AppRepository,服務執行中檔案是鎖住的。原本打算進 WinRE(修復環境)離線複製,結果進階選項裡只有「啟動設定」和「UEFI 韌體設定」,沒有命令提示字元。reagentc /info 顯示 WinRE 是 Disabled,執行 reagentc /enable 則回答:
Windows RE 無法在已啟用 BitLocker 磁碟機加密的磁碟區上啟用
我們不想為了複製檔案去動分割區或解除加密,於是改用磁碟區陰影複製(VSS):替 C 槽拍一張快照,從快照裡把整個資料夾複製出來,用完就刪掉快照。整個過程 5 秒,1,703 個檔案、114.84 MB,失敗 0 個。
腳本重點如下(系統管理員 PowerShell;目的資料夾請自行修改):
$r = Invoke-CimMethod -ClassName Win32_ShadowCopy -MethodName Create `
-Arguments @{ Volume = 'C:\'; Context = 'ClientAccessible' }
$s = Get-CimInstance Win32_ShadowCopy | Where-Object { $_.ID -eq $r.ShadowID }
cmd /c mklink /d C:\ShadowAppRepo_tmp "$($s.DeviceObject)\"
robocopy C:\ShadowAppRepo_tmp\ProgramData\Microsoft\Windows\AppRepository `
D:\Backup\AppRepo_original /E /B /COPY:DAT /DCOPY:T /R:0 /W:0 /NP /LOG:D:\Backup\robocopy.log
cmd /c rmdir C:\ShadowAppRepo_tmp # 只移除連結
$s | Remove-CimInstance # 刪除這次建立的快照
注意:
---
◆ 06 在複本上逐表、逐筆找壞掉的地方
AppRepository 裡有兩個主要資料庫:
Deployment.srd 有 30 個資料表和索引,只有一張「File」資料表讀不出來。File 有 83,042 筆,逐筆讀過一次,只有 1 筆損毀:

| 欄位 | 內容 |
|---|---|
| _FileID | 1309873 |
| Package | 7406(對照 Machine.srd:MicrosoftTeams_25331.1101.4152.8047_x64__8wekyb3d8bbwe) |
| RelativeFilePath | desktop-assets\hashed-assets\207209-670a38f0b67525ab.js.gz |
| 狀況 | 讀 _Dictionary 欄位時回報 malformed;BlockSize 讀出 NULL(定義是 NOT NULL) |
import sqlite3, sys
db = sqlite3.connect(sys.argv[1]) # 傳入「複本」的 StateRepository-Deployment.srd
print("integrity_check:", db.execute("PRAGMA integrity_check").fetchall()[:3])
for (t,) in db.execute("SELECT name FROM sqlite_master WHERE type='table'").fetchall():
try:
print("OK ", t, sum(1 for _ in db.execute(f'SELECT * FROM "{t}"')))
except sqlite3.DatabaseError as e:
print("FAIL", t, e)
rowids = [r for (r,) in db.execute("SELECT rowid FROM File")]
for rid in rowids:
try:
db.execute("SELECT * FROM File WHERE rowid=?", (rid,)).fetchall()
except sqlite3.DatabaseError as e:
print(rid, e, db.execute("SELECT Package, RelativeFilePath FROM File WHERE rowid=?", (rid,)).fetchall())
print("File rows:", len(rowids))
整張表讀不完時,只讀 rowid 通常還走得過去;再一筆一筆讀整列,就能把壞的那筆找出來。
同一個資料夾裡還有一個 512 bytes 的 StateRepository-Deployment.srd.upgrade,修改時間正好是 11/6 07:08,和那次失敗同時。我們的推測是:服務啟動時要把資料庫升級成新的結構,以 .upgrade 為新檔,把舊資料「INSERT INTO main.File … FROM Source.File」整批搬過去,搬到這一筆就失敗,整個更新跟著回滾。這可以解釋事件記錄裡那句 SQL,但只是推測,沒有直接證據。
我們在拋棄式複本上模擬了這次搬移:
| 情境 | 完整性檢查 | 模擬搬移 |
|---|---|---|
| 原狀 | malformed | 失敗(和 Windows 的錯誤相同) |
| 只把壞欄位設成 NULL | NULL value in File.BlockSize | 失敗(NOT NULL 限制) |
| 刪掉壞的那 1 筆 | ok | 成功(83,041 筆) |
| 刪掉這個 Teams 的全部 6,917 筆 | ok | 成功(76,125 筆) |

---
◆ 07 最小的修復:不改資料庫,讓 Windows 自己移除
直接用 SQLite 改正式資料庫(刪掉那一筆)是最快的,但我們沒有這樣做:資料庫之間、登錄和套件狀態之間的關聯我們看不到,改壞了更難收拾。比較穩的做法是用 Windows 正規的方式移除這個 Teams,讓服務自己清掉相關記錄。
動手前 Codex 加了幾個條件:
盤點結果:
Get-AppxPackage -AllUsers -Name MicrosoftTeams
PackageFullName : MicrosoftTeams_25331.1101.4152.8047_x64__8wekyb3d8bbwe
PackageUserInformation : {S-1-5-18 [S-1-5-18]: Staged}
Get-AppxProvisionedPackage -Online | Where-Object DisplayName -eq MicrosoftTeams
PackageName : MicrosoftTeams_25331.1101.4152.8047_x64__8wekyb3d8bbwe
S-1-5-18 是系統帳戶,狀態是 Staged(已放好檔案、還沒註冊給任何人);另外它在預先佈建清單裡,準備給之後新建的帳戶用。也就是說,沒有任何使用者註冊這個版本的 Teams。
於是只執行一行:
Remove-AppxProvisionedPackage -Online -PackageName 'MicrosoftTeams_25331.1101.4152.8047_x64__8wekyb3d8bbwe'
約 5 秒完成,回傳 RestartNeeded: False。再盤點一次,兩份清單裡都沒有它了(連 Staged 都消失),所以原本準備的第二步 Remove-AppxPackage -AllUsers 就沒有執行。
第二張快照的檢查結果:

---
◆ 08 更新成功
重試原本失敗的更新:2026-10 預覽更新 KB5127936(26200.9818)「已順利在 2026/11/6 安裝」。Windows Update 顯示「您現在為最新狀態」,之前一直被鎖住的「暫停更新」按鈕也恢復可以按了。

最後用 ◆03 的指令查 13:00 之後的 StateRepository 事件 107/227:沒有任何輸出。
---
■ 這次學到的五件事

---
■ 這次沒有解決、也不能下結論的事

■ 如果你也遇到類似狀況
---
■ 參考連結
(記錄、指令輸出與數字都是我們自己這台筆電的實測,歡迎討論或指正。)
線上





