---
title: "B 案生死驗證：WSL2＋docker engine 無人登入常駐實測（FR-066.7 T-7.4 / CM-1346）"
brand: "Guidant AI · **FR-066** 檢測 Agent 原生安裝包"
eyebrow: "FR-066.7 T-7.4 · B 案生死驗證 · 2026-08-23"
h1: "B 案生死驗證：WSL2＋docker engine 撐不撐得住無人登入"
lede: "在 192.168.50.160 開一個獨立 WSL distro，裝 systemd＋docker-ce，把 onepack 兩容器跑起來並 enroll 上 188 DEV，然後專攻一題：**沒有人登入時，這套東西能不能自己活著**。答案是**不能**——不是設定沒調好，而是 WSL 會在閒置約 60 秒後把 distro 的 userspace 凍結，且 `restart: unless-stopped`、systemd enable、`vmIdleTimeout=-1`、distro 內常駐 anchor 進程**四種手段全部無效**。B 案在生死題上失敗。"
chips: [
  {text: "實測紀錄・非設計文件", kind: warn},
  {text: "對應卡：CM-1346（T-7.4）", kind: plain},
  {text: "判定：B 案不可行", kind: warn}
]
footer: "FR-066.7 T-7.4 · B 案生死驗證 · 2026-08-23 · 實測值以本文件為準"
---

> 🔴 **本文件記錄「B 案能不能成立」，不是「客戶要這樣裝」。** 探路階段允許權宜手段
> （改埠避開既有 agent、SSH 遠端下指令、手寫 .env）；權宜處一律標示 ⚠️**探路權宜**，
> 與「結論」分開寫。體例沿用 `t71-windows-probe.md`。
>
> 對應：design.md **D18**（B 案否決的理由之一是「常駐機制未驗」——本卡即為補驗）、
> **D17**（Docker Desktop 路線）、`t71-windows-probe.md` §8（A 案登出全滅 P0）。

## 0. 結論總表（30 秒版）

| # | 驗證項 | 實測結論 | 卡點等級 |
|---|--------|---------|---------|
| ① | **佈建** | ✅ **通**。獨立 distro `guidant-wsl`（Ubuntu 24.04）＋systemd＋docker-ce 29.7.2＋compose v5.5.0；onepack 兩容器 healthy、enroll 上線 188 DEV（`remote_agents` id=8 `WIN160-WSL-B`）。既有 Docker Desktop 完全未受影響 | 低（純安裝面無擋路） |
| ② | 🔴 **無人登入常駐（核心生死題）** | ❌ **不通，且比 A 案更難救**。(a) SYSTEM 帳戶排程**被 WSL 硬拒**（`WSL_E_LOCAL_SYSTEM_NOT_SUPPORTED`）；(b) 改 S4U 具名帳戶排程可跑 wsl.exe，但 **WSL 在閒置約 60 秒後凍結 distro userspace**；(c) `restart: unless-stopped`／systemd enable／`vmIdleTimeout=-1`／distro 內 anchor 進程**四種手段全失效**；(d) 反證測試排除「S4U 設定造成」的替代解釋 | **極高（P0，B 案的死因）** |
| ③ | **網路** | ⚠️ **有條件通，且比 A 案退步**。WSL2 NAT 只轉 localhost，**LAN 介面完全沒有 listener**，雲端連不到；需 `netsh portproxy` 補一層，且 WSL IP 是 DHCP、每次開機要重設。`mirrored` 模式此機**不支援**（`0x803b0015`，還會退化成 networkingMode=None） | 中（可解但增維運面） |
| ④ | **指紋** | ✅ 行為明確。`/sys` 在 WSL 內同樣唯讀、`product_uuid` 不存在（同 T-7.1 硬失敗，該掛載行必須拿掉）；退化成 machine-id 單源，而該 machine-id 是 **distro 自己的**（import 時生成），非 Windows 主機任何值。獨立驗算相符 | 低（行為與 A 同構，可預期） |
| ⑤ | **韌性（冷重開機）** | ⏸️ **未測**——②已判死，此題失去決策意義（詳 §7） | — |
| ⑥ | **B 案可行性判定** | 🔴 **不可行**。見 §8 一句話判定 | — |

**一句話判定**：**B 案不可行**——WSL VM 的生命週期由 Windows 側常駐進程決定，而「Windows 側常駐進程」正是無人登入場景所缺的那樣東西，因此 B 並未繞開 A 的死穴，只是把「需要有人登入」換成「需要一個永不結束的 Windows 側進程」，而工作排程器（跑完即結束的模型）給不了它。

---

## 1. 環境與佈建實況

### 1.1 現場既有狀態（開工前盤點）

| 項目 | 實測 |
|------|------|
| OS | Windows Server 2025 Standard（10.0.26100.4652），機器名 `JEDI-WIN2025-01-AD`，網域 `jedicogy.com` |
| WSL | 2.7.12.0，kernel 6.18.33.2；`WSLService` Automatic/Running |
| 既有 distro | `Ubuntu`、`docker-desktop` — **屬 `raymond` 的 per-user 註冊**（見 §1.2） |
| 既有 Docker Desktop | 執行中（7 進程），agent 容器在 8443 |
| 記憶體 | 24GB（實測期間 free 約 16GB） |
| onepack | `C:\onepack\guidant-agent-compose-0.2.28`，sha256 與 `.sha256` 檔**相符**（`0b5d47f0…`，即 T-7.1 那顆，未重搬） |

### 1.2 🆕 WSL distro 是 per-user 註冊（B 案佈建的第一個結構事實）

以 `Administrator` 身分執行 `wsl -l -v` 回**沒有任何 distro**，但 `raymond` 有兩個。
查註冊表證實 distro 掛在各使用者 SID 下：

```
HKEY_USERS\S-1-5-21-…-1101\…\Lxss   → docker-desktop, Ubuntu   （raymond）
HKEY_USERS\S-1-5-21-…-500\…\Lxss    → （空，Administrator）
```

**意義**：B 案的 distro 必須註冊在「執行排程工作的那個帳戶」名下；換帳戶跑就看不到它。
這也順帶保證了本次探路的隔離性——新開的 `guidant-wsl` 在 Administrator 名下，
**`raymond` 的 Docker Desktop 兩個 distro 全程未被觸碰**。

### 1.3 佈建步驟與耗時（皆一次成功，無擋路項）

| 步驟 | 作法 | 耗時 |
|------|------|------|
| 取得 rootfs | `cloud-images.ubuntu.com/wsl/releases/24.04/current/ubuntu-noble-wsl-amd64-24.04lts.rootfs.tar.gz`（340MB） | 45 秒 |
| import distro | `wsl --import guidant-wsl C:\t74\wsl\guidant <rootfs> --version 2` | 34 秒 |
| 開 systemd | 寫 `/etc/wsl.conf`（`[boot] systemd=true`）→ `wsl --terminate` → 再進入 | 數秒 |
| 驗 systemd | `ps -p 1 -o comm=` = `systemd`；`systemctl is-system-running` = `running` | — |
| 裝 docker-ce | 官方 apt repo（`download.docker.com/linux/ubuntu noble stable`）→ `systemctl enable --now docker` | 108 秒 |
| 版本 | docker **29.7.2**（client＝server）、**Docker Compose v5.5.0**、`enabled`/`active` | — |
| `docker load` 兩顆 image | 從 `/mnt/c/onepack/...` 讀 3.32GB＋188MB | **約 12 分鐘**（比 T-7.1 的 6 分鐘慢一倍，因走 `/mnt/c` 的 9p 檔案系統） |
| `compose up -d` | 兩容器建立並轉 healthy | 約 45 秒 |

**⚠️ 對日後任何 WSL 路線的規格輸入**：交付包放在 Windows 檔案系統（`/mnt/c`）時
`docker load` 明顯變慢；若真要走 WSL 路線，應先把 tar 複製進 distro 的 ext4（`/root` 之類）再 load。

### 1.4 ⚠️探路權宜：與既有 agent 並存的處置

160 上已有 Docker Desktop 版 agent 佔用 8443，且**其 `.env` 指向 `https://192.168.50.191`**
（`guidant-ai-prd-01`，非 T-7.1 記載的 188——該設定在 T-7.1 之後被改過）。
本卡**未動那份設定、未動那組容器**，改為：

- 另開安裝目錄 `C:\t74\b`（`.env` + `docker-compose.yml` + `certs-in/`）
- 埠位移：資料面 **9443**（原 8443）、SeaweedFS **28333/28888/29333**
- 雲端指向 **188 DEV**（`.env`、CA 與註冊 token 取自 188 上 `/tmp/t66-final/` 的既有安裝）
- `AGENT_HOSTNAME=WIN160-WSL-B`（雲端可一眼分辨是哪一路線）

### 1.5 佈建結果（①的驗收證據）

```
INFO:agent:device_uuid computed: 5bd79796b9b2b1687fff565af29ca46cb1a00862b7f5a7a7d7e8195ef40ed0ed
INFO:agent:agent enrolled: agent_uid=642f815e-a3c8-4ee6-9863-f6c347fe2875 heartbeat=300s
INFO:agent:data-plane mTLS listening on 0.0.0.0:8443 (client certificate required)
INFO:agent:agent auth ready (mode=full, status=active, ...)
[integrity] 完整性驗證通過（114 個檔案，版本 0.2.28，kid 04b1e65f100c6c8f）
```

雲端 188 DEV（`guidant_ai.compliance.remote_agents`）：

```
 id |     name     |          base_url           |        fp        | status
  8 | WIN160-WSL-B | https://192.168.50.160:9443 | 5bd79796b9b2b168 | active
```

**✅ ①結論**：docker engine on WSL2 這條路，**安裝面完全走得通**，
且 agent 對 engine 與對 Docker Desktop 沒有任何行為差異（防竄改驗章、enroll、mTLS 全正常）。

---

## 2. 🔴 查證②：核心生死題（本卡的主結論）

### 2.1 第一層：SYSTEM 帳戶排程 —— 被 WSL 硬拒

卡片設計的做法是「工作排程器（SYSTEM 帳戶、不論使用者是否登入、開機觸發）」。
實測以 SYSTEM 身分執行 `wsl.exe`：

```
Running WSL as local system is not supported.

Error code: Wsl/WSL_E_LOCAL_SYSTEM_NOT_SUPPORTED
```

`wsl -l -v`、`wsl --status` 皆同一錯誤。

**這不是權限沒調好或環境沒裝好，是 WSL 明文不支援 LOCAL SYSTEM。**
卡片寫的那個做法**不存在可行版本**，必須換帳戶模型。

### 2.2 第二層：S4U 具名帳戶排程 —— 可以跑 wsl.exe

改用 `Register-ScheduledTask` 搭 **S4U**（Service-for-User，不需存密碼）：

```powershell
$p = New-ScheduledTaskPrincipal -UserId 'JEDICOGY\administrator' -LogonType S4U -RunLevel Highest
```

實測結果（工作內容印出自身身分）：

```
whoami: jedicogy\administrator
sessionid: 0
--- wsl --status ---   Default Version: 2      ← 有回應，不再被拒
```

**✅ 這一層通了**：具名帳戶＋S4U＋session 0，可以在無互動 session 的情況下呼叫 `wsl.exe`。
（附註：`schtasks /RU <user> /NP` 這種寫法在 Server 2025 上被拒；要用 PowerShell 的
`New-ScheduledTaskPrincipal -LogonType S4U`。）

### 2.3 🔴 第三層：WSL VM 閒置自關 —— B 案死在這裡

排程能跑 wsl.exe 之後，容器也確實被拉起來了。但**放著不管，agent 就沒了**。

#### 2.3.1 先講一個差點造成誤判的陷阱（觀察者效應）

最初我用 `wsl -d guidant-wsl -- docker ps` 反覆檢查，**每次都看到容器 Up**，
看起來一切正常。露餡的是 `uptime`：**每次查詢它都從 0 重新算**。

> **`wsl.exe` 只要被呼叫就會把 distro 喚醒（resume/boot）。
> 因此任何用 `wsl.exe` 做的健康檢查，都會把「已經死掉」變成「看起來活著」。**

改用**不碰 distro 的觀測面**（Windows 側 `wsl -l --running` ＋ 雲端 DB 心跳）之後，
真相才出來。

#### 2.3.2 無干擾觀測的實測結果

| 時刻 | 觀測 | 結果 |
|------|------|------|
| 00:01:31 | 啟動 distro，之後只用 `wsl -l --running` 看 | `guidant-wsl` running |
| 00:02:35 | 同上（約 60 秒後） | **`There are no running distributions.`** |

**distro 在無人使用約 60 秒後自行停止**（WSL 預設 `vmIdleTimeout` 即 60000ms）。
agent 隨之離線——`restart: unless-stopped` 與 `systemctl enable docker` **都救不了**，
因為死的不是容器、也不是 docker daemon，是**承載它們的整個 distro**。

#### 2.3.3 🔴 更精確的機制：不是「關機」，是 userspace 被凍結

進一步解剖（在 anchor 測試失敗後、resume 當下取證）：

| 觀測面 | 值 | 意義 |
|--------|-----|------|
| `vmmemWSL` 進程 | **仍在**（start 00:07:15） | VM 外殼還在 → **只看 Windows 進程會誤判成活著** |
| `wsl -l --running` | **no running distributions** | distro 不在執行 |
| distro 內 `uptime -s` | **仍是 00:07:16**（未變） | **Linux kernel 沒有重開機** |
| 容器 `StartedAt` | **00:14:33**（＝我 poke 的瞬間） | 容器是被停掉、又在 resume 時拉起 |
| `docker.service` ActiveEnterTimestamp | **00:14:34** | systemd 的 docker 也是 resume 才 active |
| `docker inspect … RestartCount` | **0** | 不是 crash-restart |
| agent log | 最後一行 00:07:49，之後**空白 6.5 分鐘** | 期間完全沒有任何活動 |

dmesg 佐證（`[438s]` ＝ 00:14:34，即 resume 時刻）：

```
WSL (2 - init-systemd(guidant-wsl)) ERROR: WaitForBootProcess:3488:
      /sbin/init failed to start within 10000ms
```

**結論**：WSL 把 distro 的 **userspace 整個凍結/收掉**（kernel 與 VM 外殼保留），
**裡面沒有任何一層還醒著能自救**——docker daemon 自己也被凍結了。
這比單純「關機」更棘手：關機至少可以靠「開機自起」補救，凍結則是**連自起的那個東西也被凍住**。

### 2.4 四種挽救手段，全部實測無效

| # | 手段 | 實測結果 |
|---|------|---------|
| 1 | compose `restart: unless-stopped` | ❌ 無效——死的不是容器 |
| 2 | `systemctl enable docker`（開機自起） | ❌ 無效——distro 不「開機」，是被凍結 |
| 3 | `%USERPROFILE%\.wslconfig` → `[wsl2] vmIdleTimeout=-1` | ❌ **無效**，實測 2 分鐘內照樣停止 |
| 4 | distro 內常駐 anchor 進程（`sleep infinity`，模仿「保持忙碌」） | ❌ **無效**——anchor 自己也被凍結/收掉（測後 Windows 側已無該 wsl.exe 進程）；心跳停在 00:07:45，6 分鐘無更新 |

**手段 4 失敗的原因，正是本案最核心的結構問題**：
放在 distro **裡面**的東西，無法阻止 distro 被凍結——它跟著一起被凍。

#### 2.4.1 反證測試：排除「是 S4U 排程設定造成的」這個替代解釋

手段 4 的 anchor 原本由 S4U 排程啟動，因此需排除一個可能：
**會不會是排程工作結束時把 distro 一起收掉了**（而非 WSL 本質行為）？

實測：**停掉 watchdog**，改從 SSH session（非排程）啟動同一支 anchor，只用無干擾觀測面看心跳。

| 時間 | 心跳 age | 判讀 |
|------|---------|------|
| 00:21:30（2 分） | 126s | 未定論（< 300s 心跳間隔） |
| 00:23:30（4 分） | 247s | 接近上限 |
| 00:25:31（6 分） | **368s** | ❌ **已超過 300s 間隔 → agent 停止回報** |

事後檢查：`wsl -l --running` = 無執行中發行版；SSH 啟動的那支 anchor 進程**同樣消失**
（Windows 側只剩 Docker Desktop 於 14:49 啟動的 4 個 wsl.exe）。

**✅ 反證成立**：換一個啟動者（SSH session 取代 S4U 排程）結果完全相同，
**死因是 WSL 的 VM 生命週期本身，不是排程工作的 context**。

### 2.5 最後一搏：1 分鐘外部 watchdog —— 機制可行，但那不叫常駐

改成 S4U 排程每分鐘跑一次，主動偵測並復活（偵測 distro/anchor 狀態 → 重拉 → 補 portproxy）。
機制本身正確運作，但 `boot.log` 揭露了真相——**每一個 tick 都報告「已經死了」**：

```
00:16:32  distro running: False   anchor alive: False → anchor (re)launched → stack 回來
00:17:33  distro running: False   anchor alive: False → anchor (re)launched → stack 回來
```

即 distro **撐不過每次 tick 之間的不到 60 秒空檔**。

> ⚠️ **這不是「常駐」，是「每分鐘重開機一次」。** 後果：
> - agent 每分鐘經歷一次容器停／起，心跳不連續
> - **執行中的檢測任務會被腰斬**（CINC/nmap 掃描動輒數分鐘）
> - SQLite 與上傳中的證據檔在反覆硬停下有損毀風險
> - 雲端顯示的 `active` 是**假象**——是被 watchdog 戳出來的，不是它自己活著

### 2.6 對照組：為什麼 Docker Desktop 的 distro 撐得住？

同一台機器上，`raymond` 的 Docker Desktop VM **從 14:49 活到隔日 00:20（約 10 小時）未死**，
而 B 的 distro 撐不過 60 秒。差別**不在 WSL 設定**，而在：

> Docker Desktop 有 **`com.docker.backend`——一個 Windows 使用者態的常駐進程**（實測 7 個進程），
> 持續與 VM 通訊，所以 VM 一直「忙著」。B 案沒有這種 Windows 側常駐元件：
> 工作排程器是「跑完就結束」的模型。

**這一點把 A 與 B 的死因統一了**：兩者其實是同一個結構事實的兩面——
**WSL VM 需要一個 Windows 使用者態的常駐看護，而「Windows 使用者態常駐」與「無人登入」本質衝突**。
B 案並沒有繞開 A 的死穴，只是把「需要 Docker Desktop 且需要有人登入」
換成「需要一個永不結束的 Windows 側進程」——而排程器給不了它。

---

## 3. 查證③：網路（比 A 案退步）

| 觀測 | 結果 |
|------|------|
| WSL distro 內 | `docker-proxy` LISTEN `0.0.0.0:9443` ✅（**但這是 WSL 的網路命名空間內**） |
| Windows 側 `netstat :9443` | **完全沒有 listener** ❌ |
| Windows 本機 `127.0.0.1:9443` | ✅ True（WSL 的 localhost forwarding 自動生效） |
| Windows 本機 `192.168.50.160:9443` | ❌ **False** |
| 188 → 160:9443 | ❌ **TCP 不通** |

**根因**：WSL2 NAT 模式只做 **localhost** 轉送，**不會**把容器埠曝露到 LAN 介面。
這與 T-7.1 §5.1 的 Docker Desktop 行為（自動綁 `0.0.0.0`、Windows 側看得到 listener）
**明確不同——B 在此退步**。

### 3.1 兩條解法實測

| 方案 | 結果 |
|------|------|
| `networkingMode=mirrored`（理論上最乾淨） | ❌ **此機不支援**：`CreateInstance/CreateVm/ConfigureNetworking/0x803b0015`，且**退化成 `networkingMode=None`（更糟）**。已還原 |
| `netsh interface portproxy`（v4tov4） | ✅ **可行** |

portproxy 生效後（另加一條 inbound 防火牆規則 `Guidant AI Agent B-case (9443)`）：

```
188 → nc -z 192.168.50.160 9443     → OPEN
188 → openssl s_client               → CONNECTION ESTABLISHED, TLSv1.3
   peer cert CN = 5bd79796…（＝agent 指紋）
   issuer   CN = Guidant Agent CA (onprem-188)
```

### 3.2 ⚠️ portproxy 的維運代價（若日後任何 WSL 路線復活，這是硬規格）

WSL 的 `eth0` 是 **DHCP**（本次 `172.31.22.105/20`），**每次 distro 啟動可能換 IP**，
而 portproxy 規則寫死了目標 IP → **規則會靜默失效**（TCP 連到黑洞，症狀是「雲端連不上但本機看起來正常」）。
因此安裝程式必須每次開機重算並更新規則（本次 watchdog 腳本已內建此邏輯並實測可運作）。

---

## 4. 查證④：指紋

| 項目 | 實測 |
|------|------|
| `/sys/class/dmi/id/product_uuid` | **不存在**；且 `/sys` 是 sysfs，**root 也不可寫**（`mkdir /sys/class/dmi: Operation not permitted`） |
| 對 compose 的影響 | 與 T-7.1 §3.1 **同樣是啟動硬失敗**，該掛載行必須拿掉（160 上這行在 T-7.1 已被註解，本次沿用） |
| agent 行為 | `WARNING:agent:device fingerprint source unreadable (/host/product_uuid)` → graceful 退化成單源 |
| distro `/etc/machine-id` | `21e1a92684b84f05aceba8f5d1f7276e`（**import 時生成，非 Windows 主機任何值**） |
| agent `device_uuid` | `5bd79796b9b2b1687fff565af29ca46cb1a00862b7f5a7a7d7e8195ef40ed0ed` |
| **獨立驗算** | `sha256("" + "\|" + machine-id)` = `5bd79796…` ✅ **完全相符**（同 T-7.1 §3.3 的退化公式） |

**與 A 案對照**：兩者都**不是** Windows 主機身分——
A 綁在 `docker_data.vhdx`（machine-id `650cb79d…`），B 綁在 `guidant-wsl` distro 的 vhdx。
**漂移條件**：`wsl --unregister` 後重 import 必然換一顆 machine-id，等同 A 的 factory reset。

> ⚠️ **`wsl --unregister` 漂移未實機執行**：該操作會摧毀現場，而②已判死，
> 保留現場的價值高於補一個可從機制上確定的結論（machine-id 由 import 時生成，重 import 必變）。
> 此項標記為**推定、未實測**。

---

## 5. 佈建與資源成本觀察

| 項目 | 實測 |
|------|------|
| WSL VM 數量 | **兩顆並存**：B 的（0.79–0.91GB，start 00:07）＋Docker Desktop 的（1.74GB，start 14:49） |
| 意義 | B **不是取代 A 的 VM，而是再開一顆**；24GB 機器上兩顆約 2.5GB |
| Docker Desktop 影響 | ✅ **全程無影響**（7 進程健在、8443 仍 listening、distro 未被觸碰）——demo 環境安全 |

---

## 6. 探路權宜清單（正式交付不得沿用）

| # | 權宜手段 | 正式做法應為 |
|---|---------|-------------|
| 1 | 埠改 9443/283xx 避開既有 agent | 正式部署用標準埠；本次僅為與 demo 環境並存 |
| 2 | `.env`／CA／註冊 token 從 188 既有安裝複製 | 正式走安裝程式互動問答＋TOFU 憑證確認 |
| 3 | 全程 SSH 遠端下 PowerShell 指令（經 188 跳板） | 正式不要求客戶開任何終端 |
| 4 | rootfs 直接從 cloud-images.ubuntu.com 下載 | 封閉網路客戶需離線 rootfs（**本身即 B 案的另一項成本**） |
| 5 | compose 檔沿用 T-7.1 已註解 product_uuid 的版本 | 出 Windows 專用 compose 檔（T-7.1 §3.5 已定調） |

---

## 7. 未實測項（逐條列出，不當成已驗）

1. **登出／冷重開機不登入**（原驗證清單②的後兩個情境）——**未執行**。
   理由：②已在更前面的一層判死（**閒置 60 秒即凍結**，比「登出才死」嚴重得多），
   且該兩項會中斷決策者的 RDP session／使機器離線數分鐘，**成本高而不會改變結論**。
   ⚠️ 嚴格說，「冷重開機後排程器能否拉起」仍是未證項；但即使能拉起，
   拉起後也只會回到 §2.5 的「每分鐘重開機一次」狀態。
2. **Windows Update 等級重開機的韌性**（原⑤）——同上，未測。
3. **`wsl --unregister` 指紋漂移**——推定必變，未實機執行（見 §4）。
4. **把 anchor 包成 Windows 服務**（WinSW/NSSM）——**未測**，理由見 §8.2。
5. **派檢測任務端到端**——未做。②判死後，端到端只能證明「戳醒時能用」，不能證明常駐。
6. **B 在真正乾淨機（無 Docker Desktop）上的行為**——本次是與 DD 並存的環境；
   推定 WSL 生命週期行為一致（與 DD 無關），未驗。

---

## 8. B 案可行性判定

### 8.1 判定

> 🔴 **B 案（WSL2＋docker engine＋工作排程器常駐）不可行。**
>
> 依據：無人值守常駐是本案的**存在理由**（B 相對 A 的唯一賣點就是解 A 的登出全滅 P0）。
> 實測顯示 B 不但沒解掉，還把問題**惡化**——A 至少在有人登入時能穩定長跑（DD 的 VM 實測 10 小時未死），
> B 則是**閒置 60 秒就凍結**，只能靠外部 watchdog 每分鐘復活一次，
> 代價是心跳不連續、長時間檢測任務會被腰斬。

### 8.2 唯一未測的殘存候選，以及為何不建議追下去

理論上還剩一招：**把「握著 distro 的那隻手」做成 Windows 側常駐服務**
（用 WinSW/NSSM 把 `wsl.exe -d guidant-wsl -- sleep infinity` 包成 Windows Service），
結構上模仿 Docker Desktop 的 `com.docker.backend`。這**有機會**成立（未測）。

但即使成立，也不建議：

1. **它要用的正是 FR-066.8（T-8.3）的 WinSW 工**——同一份服務化工程投入，
   B 換來的是 **Windows 服務 → wsl.exe → WSL VM → systemd → docker → 容器（六層）**，
   原生版換來的是 **Windows 服務 → agent.exe（兩層）**。
2. 六層各有自己的失效模式與觀測面（本卡已示範：光是判斷「它到底活著沒有」就有觀察者效應陷阱），
   查修成本高，且**這些成本對原生版零複用**。
3. 網路仍需 portproxy＋每次開機重算 IP；指紋仍是 VM 值；封閉網路還要額外備 rootfs。

**這與 D18 當初否決 B 的理由（「常駐機制未驗、四層架構查修成本高、指紋仍是 VM 值、對原生版零複用」）
完全一致——本卡把其中「未驗」那一項補成了「已驗且失敗」。**

### 8.3 對 D18 的回饋

D18 是在「B 案常駐機制未驗」的前提下做的裁示。本卡結論**支持並強化該裁示**：

- D18 對 B 的判斷**正確**，且理由可從「推測」升級為「實測」。
- 建議在 design.md D18 的「①②③④被排除選項」處，把 B 的排除理由補一句
  **「常駐機制經 T-7.4 實測否證（CM-1346）」**並指向本文件。
- **A（Docker Desktop）作為 demo/PoC 限定的定位不變**且更站得住：
  A 在有人登入時穩定（實測 10 小時），B 連這點都做不到。

### 8.4 若首腦仍決定立 B 案，工作清單修正建議

（本節僅為完整性；以本卡結論**不建議**立案。若仍要立，下列為**必要**而非充分條件。）

| # | 相對 CM-1338/1339 需**新增**的工作 | 理由 |
|---|-----------------------------------|------|
| 1 | **Windows 常駐服務（WinSW/NSSM）包 wsl.exe 保活** — 且需先做可行性實測 | §8.2；沒有它 B 不成立，而它本身未驗 |
| 2 | 帳戶模型改 **S4U 具名帳戶**（不可用 SYSTEM），含帳戶生命週期（改密碼／停用／網域政策）的處置 | §2.1；SYSTEM 被 WSL 硬拒 |
| 3 | **portproxy 生命週期管理**（每次開機重算 WSL IP、更新規則、失效偵測） | §3.2 |
| 4 | **離線 rootfs 供裝**（封閉網路客戶無法連 cloud-images） | §6 第 4 項 |
| 5 | **WSL distro 註冊在正確帳戶**的安裝邏輯（per-user 註冊） | §1.2 |
| 6 | Windows 專用 compose 檔（拿掉 product_uuid 掛載） | §4（與 T-7.1 §3.5 同一項） |
| 7 | **常駐性回歸測試機制**（且必須用無干擾觀測面） | §2.3.1 觀察者效應——沒有它，回歸測試會一直報「正常」 |

---

## 9. 方法論教訓（跨案通用，建議留存）

> **判斷 WSL 上的常駐性，不能用 `wsl.exe` 觀察——它會把 distro 喚醒，
> 把「已經死了」變成「看起來活著」。**

可用的無干擾觀測面：

| 觀測面 | 可信度 |
|--------|--------|
| 雲端 DB `remote_agents.last_seen_at`（心跳，間隔 300s） | ✅ 最可信；但**判讀要等足夠久**（age < 300s 不代表健康） |
| Windows 側 `wsl -l --running`（只讀清單） | ✅ 實測不會喚醒 distro |
| Windows 側 `Get-Process vmmemWSL` | ⚠️ **會誤導**——VM 外殼可留著但 userspace 已凍結 |
| distro 內 `uptime -s` vs 容器 `StartedAt` 交叉比對 | 🔍 事後解剖有效，但取證動作本身會 resume |

同一個陷阱在本卡出現**兩次**（先誤判 distro 活著、後誤判 anchor 有效），
兩次都是靠「換一個不碰它的觀測面」才看破。

---

## 10. 160 機上的本卡殘留物（保留現場，等首腦裁示）

| 項目 | 位置／名稱 | 建議 |
|------|-----------|------|
| WSL distro | `guidant-wsl`（Administrator 名下），`C:\t74\wsl\guidant` | 裁示後 `wsl --unregister guidant-wsl` 可完整清除 |
| 安裝目錄 | `C:\t74\b`（`.env` 含註冊 token 與 SeaweedFS 憑證，**未入版控**） | 清除時一併刪 |
| rootfs 與腳本 | `C:\t74\wsl\*.tar.gz`、`C:\t74\*.ps1`、`C:\t74\boot.log` | 可刪 |
| 排程工作 | `T74-GuidantWslKeepalive`（**目前已 Disabled**）、`t74s4u`、`t74probe0` | **可刪**（探路權宜，非產品的一部分） |
| 防火牆規則 | `Guidant AI Agent B-case (9443)` | **可刪**（A 案的 `…data plane (8443)` 那條**請保留**，屬 T-7.1） |
| portproxy | `0.0.0.0:9443 → 172.31.22.105:9443` | 可刪（`netsh interface portproxy delete v4tov4 listenport=9443 listenaddress=0.0.0.0`） |
| `.wslconfig` | `C:\Users\Administrator\.wslconfig`（`vmIdleTimeout`） | 可刪；**`raymond` 從頭到尾沒有這個檔，未被影響** |
| DEV 雲端資料 | `guidant_ai.compliance.remote_agents` id=8 `WIN160-WSL-B` | 建議驗收後清 |

🔴 **未動的東西**（確認清單）：`raymond` 的 `Ubuntu`／`docker-desktop` distro、
Docker Desktop 本體與其容器、`C:\onepack\` 內容、8443 那條防火牆規則、
191／STG／POC 任何環境（全程只讀 188 DEV，寫入僅 agent 自行 enroll 產生的 id=8 一筆）。
