# P0 复盘簿

> 每次 P0 修完在这里记一笔:症状 → 根因 → 为什么会发生(流程层面) → 对应守则。
> 目的不是追责,是让同一类错误只交一次学费。新条目追加在最上面。

## 2026-07 · XSETTINGS DPI 单位错误(史上最大,v1.2.9~v1.3.1)

- **症状**:微信点公众号/附件/小程序窗口秒关或白屏(amd64/arm64 都中);Chromium 实例整体黑屏崩溃循环;issue #111 及大量群反馈。
- **根因**:#101 引入的 xsettingsd 配置写 `Xft/DPI 96`,而 XSETTINGS 规范单位是 **DPI×1024**(应为 98304)。所有 Chromium 内核应用把 DPI 读成 0.09 → 缩放因子≈0 → 显示变换矩阵不可逆(`transform.cc NOTREACHED`)→ GPU/viz 进程连崩 → 窗口/应用退出。
- **连带**:崩溃风暴 × docker 日志无上限 × 崩溃转储无 TTL × 悬空镜像不回收 → 用户磁盘被吃(「1TB 没了」);同步升级接口在受限网络下表现为「一键升级卡死」。
- **为什么会发生**:AI 生成 PR 的配置数值未对规范验证(R7);冒烟只测了「微信启动」没测「点开公众号」(R9);第一次修复(v1.3.1 的 `--force-device-scale-factor=1`)用只解释部分症状的理论当根因发布(R6);四个版本挤在 48h 发布,事故窗口内变更太多难以二分(R8)。
- **修复**:`94b591e`(单位改 98304 两处写入点 + 日志上限 + 转储 TTL + 悬空镜像回收 + 升级异步化)。
- **守则**:R3 / R4 / R6 / R7 / R8 / R9。

## 2026-06-25 · 面板自更新后全员 502 黑屏(v1.2.6 修复)

- **症状**:用面板内「一键更新」升级的用户,更新后所有实例远程桌面黑屏、「桌面服务暂不可用」;直接 `docker pull` 的用户无恙。
- **根因**:自更新克隆旧容器配置时把 `Hostname`(= 旧容器短 id)一并克隆;新面板容器的 hostname 于是指向一个已删除的容器 → `ensureNetwork()` 用 `getContainer(hostname())` 自我定位 404 → 返回 null → 新建实例落到默认 bridge 网络 → 面板按容器名反代解析不到 → 502。
- **为什么会发生**:自身状态靠「克隆运行时环境」而非声明式重建;自我定位单点依赖 hostname 无兜底。
- **修复**:`7e21aca`(重建不再 pin Hostname;ensureNetwork 增加按容器名 `woc-panel` 兜底)。
- **守则**:R2。

## 2026-06~07 · 桌面连接/重连卡死连环修(4 连击)

- **症状**:切实例 A→B→A 卡死、重连后 Xvnc 卡死、输入模式切换不生效等,先后修了 4 次(`13ec0bd`→`855997f`→`7fecc09`→`b0511f5`)。
- **根因**:noVNC/iframe 的连接生命周期管理散落多处,每次只修当时复现的那条路径。
- **为什么会发生**:补丁式响应,没有对「连接状态机」做一次性的不变式设计;每个补丁都没解释之前补丁为何不够(R6 的弱版本)。
- **守则**:R6;同类问题第三次出现时必须停下来做整体设计,而不是继续打第四个补丁。

## 2026-06 · 深色模式 portal 方案发布后撤回

- **症状**:portal 实时切换深色在极简容器里 session 总线不稳,微信也不跟随;发布(`335b839`)后撤回(`ba32cc9`)。
- **为什么会发生**:方案依赖容器里并不可靠的桌面基础设施,发布前未在目标环境充分验证。
- **守则**:R9(验证用户动作,而非「代码跑通」)。
