> ✅ **CLOSED — 2026-07-30 全案收尾**：FR-057 已隨 v1.12.0 發版（三 repo 已 push + tag），Notion CM-938~952/954/955/956 全 Done（CM-953 維持討論）。收尾彙整見同目錄 `2026-07-30-v1.12.0-release-SUMMARY.md`。本文件 §1.1/§9.1 的 push 狀態描述為當時快照，已過時。

# FR-057 全案完成 — 換 session 交接（2026-07-29）

| 項目 | 內容 |
|------|------|
| 緣由 | FR-057（OpenSCAP SSH connector）8 張子任務卡 + 3 張手測期間發現的修正卡（CM-952/954/JobExecutionDrawer 證據連動）**全部完成並已部署驗證**。本棒角色是**收口 + 部署**：完成文件補完、修 bug、build+load agent image 到兩台主機並重啟、確認服務健康。**尚未做**：user 尚未親自複測 CM-952/954 的畫面呈現（agent 才剛升級到 0.2.11）。 |
| Branch | 三 repo 皆 `feature/instance-agent`，**working tree 全乾淨、HEAD 皆已 push 到 origin**（見 §9） |
| 本棒角色 | 收口 + 部署，非新開發。下一棒可能是：user 手測回報問題需要 fix，或 user 下令走完整收尾流程（spec 已於本棒更新，但 SUMMARY / Notion 母案狀態 / memory 尚未動） |
| 接手前必讀 | 本文 §0 讀序 |
| 預估時間 | 若只是複測回報問題：10-30 分鐘理解狀況；若要做正式收尾（Notion 母案批次更新 + SUMMARY）：30-60 分鐘 |

## 🧭 原始需求 / WHY

**FR-057 = 在 FR-056 檢測工具整合平台上接入第二個掃描工具 OpenSCAP（CIS/STIG 組態合規稽核），並開出 connector 第三種連線型態 SSH。**

大圖：FR-056（已隨 v1.11.0 上線）讓租戶設定檢測工具 → 任務按「開始執行」→ 客戶端 Agent（evidence-agent，Docker）心跳領派工 → 掃描 → 報告自動回收成任務證據。第一版只有 OpenVAS（API 型）。本案價值：①客戶多了組態合規稽核能力（不只弱點掃描）②connector 架構證明可擴（SSH 型開出後，未來 Lynis 等 CLI/SSH 工具同軌）。

關鍵設計事實：
- OpenSCAP 是純 CLI 無 API、無 daemon。組態稽核必須以登入身分在目標 OS 上執行——**目標主機需一次性裝 `openscap-scanner` + SCAP content（SSG）**，這是官方正規用法（Red Hat Satellite 同模式）。Agent 維持 Docker 形態不變，只當掃描發起端。
- 憑證＝**租戶層一組共用稽核帳號**（Tenable 業界標準），金鑰/密碼二擇一推薦金鑰 + `use_sudo`，沿用 FR-056 既有 Fernet 加密鏈 + D9 派工下發。
- SCAP content 用**目標主機自帶的 SSG**（D3），不由平台推送 → 免維護版本矩陣。
- 證據＝**每台一份 HTML 原樣上傳**（D4/D5）→ result 回收鏈由單檔擴多檔（FR-057.3）。
- **D3 實作澄清**：官方 `oscap-ssh` 腳本語意是「本機 content 推送到遠端」，與 D3（用目標主機自帶 content）矛盾 → 定案 connector **自組 SSH 指令（paramiko）**直接在目標上執行 oscap 引用目標本地 content。

本棒新增的兩個重要教訓（詳見 §2）：
1. **CM-952 漏掃靜默 / CM-954 假成功報告**——兩者都是「系統回報成功但實際沒達成稽核目的」的同類問題，已修復並部署。
2. **跨平台 build 陷阱**：開發機是 Mac arm64，目標部署機是 amd64，`docker build` 沒指定 `--platform` 會產出跑不動的 image（`exec format error`），必須 `--platform linux/amd64`。

## §0 接手讀序

1. 🔒 **先懂需求 gate**：本文「🧭 原始需求」全讀 + `docs/features/FR-057-2607-openscap-ssh-connector/design.md` §1-§2（背景 + D1-D7）全讀
2. 本文 §1（現況全貌）→ §2（本棒踩過的坑）→ §3（三 repo 改動清單）→ §4（部署現況）
3. 需要深入細節才開：`docs/features/FR-057-2607-openscap-ssh-connector/handoff/2026-07-29-fr057-manual-test-handoff.md`（上一棒交接，含 connector 完整行為描述、掃描指令組法）
4. Notion 母案：`3ab346da4cd081af9cfac78397f7acfb`（CM-938）；三子需求卡 CM-939/940/941；手測發現的修正卡 CM-952（`3ac346da4cd0817c9c47e5482d12a608`）/ CM-954（`3ac346da4cd08107aa29c3819c54b19c`）/ CM-953（討論中，`3ac346da4cd0819390d2c5b85c754bf8`）

**冷接自檢**：①FR-057 解決什麼使用者問題？②為什麼 connector 自組 SSH 指令而非用官方 oscap-ssh？③CM-952 跟 CM-954 是同一類問題的哪兩種變體？④122/123 兩台 agent 主機現在跑哪個版本、健不健康？⑤下一棒該做什麼、不該做什麼？——答不出回去讀 §0.1-§0.3。

## §1 現況全貌

### 1.1 三 repo 全部完成，working tree 乾淨、已 push

| Repo | HEAD commit | 狀態 |
|------|-------------|------|
| compliance-manager-be | `0ed638a7` docs(fr057): OpenSCAP 上線文件補完——SPEC 三頁 + 使用手冊擴充 | 乾淨，已 push |
| compliance-manager-fe | `0fc8f17c` fix(job-execution-drawer): 重新整理執行紀錄時一併刷新證據清單 | 乾淨，已 push |
| evidence-agent | `722e25ca` feat(cm-954): content 對不上 OS 不再產出「假成功」報告 + bump 0.2.11 | 乾淨，已 push |

BE working tree 有一批**跟 FR-057 無關的既有 untracked 檔案**（v1.9-bugfix handoff、v1.8.0 交付文件 docx、ddd-layer-audit 資料夾等）——那些是別的 arc 留下的，不是本棒產生，**不要清理，不歸本棒管**。

### 1.2 Notion 任務卡現況

| Case | 標題 | 狀態 |
|------|------|------|
| CM-938 | FR-057 母案 | Not started（子任務全完成但母案狀態未同步——**下一棒若走完整收尾要記得改**） |
| CM-939/940/941 | FR-057.1/.2/.3 子需求卡 | Not started（同上，子任務卡本身已個別改「修正待驗證」，但這三張中層卡沒同步） |
| CM-942/943/944 | T-1.1/1.2/1.3（BE migration + FE 兩張） | 修正待驗證（已在前一棒改） |
| CM-945~949 | T-2.1~2.3（Agent connector）+ T-3.1~3.2（多檔回收鏈） | 修正待驗證（前一棒） |
| CM-952 | 多台掃描結果呈現不完整（漏掃靜默 / 報告只拿一份 / 執行紀錄不展開） | **修正待驗證**（agent 0.2.10 起含此修正，已部署 0.2.11） |
| CM-954 | content 與目標 OS 不匹配產出假成功報告 | **修正待驗證**（agent 0.2.11 含此修正，已部署） |
| CM-953 | 異質 OS（Windows）支援方案 | **討論中**，等 user 拍板要不要開獨立 FR，不是本棒可自行決定 |

**⚠️ 沒有 Notion 卡的改動**：本 session 應 user 臨時要求做的「重新整理執行紀錄時連動刷新證據清單」（FE commit `0fc8f17`）**沒有對應 Notion 卡**——這是使用者體驗微調不是正式子任務，若要正式收尾請下一棒視情況補一張小卡或併入某張既有卡的備註。

### 1.3 Agent 部署現況（本棒完成，尚待 user 手測驗收）

| 主機 | 用途 | 部署前版本 | 目前版本 | 健康狀態 |
|------|------|-----------|---------|---------|
| 192.168.50.123 | Agent 主機（jedi 帳號 SSH，路徑 `/opt/evidence-agent/deploy/`） | 0.2.10 | **0.2.11** | 已確認 `Up`，心跳 200 OK |
| 192.168.50.122 | Agent 主機（同上，路徑同） | 0.2.10 | **0.2.11** | 已確認 `Up`，心跳 200 OK |

兩台都在 0.2.11（累積含 CM-952 + CM-954 兩個修正）。**部署細節與踩過的坑見 §2.2**。

## §2 本棒踩過的坑（下一棒 / 未來部署必看）

### 2.1 CM-952 / CM-954 是同一類「靜默假陽性」問題

- **CM-952**：多台掃描中若一台失敗（SSH 不通/缺 SCAP content/非 Linux 主機），connector 逐台獨立、單台失敗只記 warning 不拖垮整批——但**原本完全沒有任何地方記錄失敗**，任務照樣顯示「成功」。修法：connector 把失敗主機清單併入 summary，FE 顯示「部分成功」+ 列出失敗主機與原因。同批也修了「報告只下載得到一份」（`report_file_uid` 單值只存第一筆，改成從 `job_evidences` 讀全部）+「執行紀錄預設不展開」（改固定展開）。
- **CM-954**：目標主機 OS 比 SSG content 新（如 Ubuntu 26.04 用 2404 content）時，`oscap` exit=0 產出完整報告，但**所有規則都因 CPE 平台判定不匹配而 notapplicable**——零實質檢查卻回報「成功」「發現 0 項」，比失敗更危險（會被當成「已檢查且乾淨」寫進稽核紀錄）。修法：事後判定（`pass+fail==0 且 notapplicable>0`）+ 事前判定（probe 階段比對 content 檔名版本 vs 目標 OS 版本）雙重把關，報告仍上傳但打 `content_mismatch` 旗標，FE 顯示「無實質檢查」警示、隱藏「發現 0 項」（避免誤讀）。

兩者刻意都**不用比例門檻**（如 notapplicable ≥95%），只認「有沒有」——因為容器化等環境本來就大量規則不適用，用比例會對合法情境誤報。

### 2.2 ⚠️ 跨平台 Docker build 陷阱（本棒親身踩雷，未來部署必看）

**第一次升級 122/123 時，容器 crash loop（`exec /usr/local/bin/python: exec format error`）**——原因是開發機（Mac，arm64）跑 `docker build` 沒指定平台，預設 build 出 arm64 image；122/123 兩台目標主機是 amd64（Linux 伺服器），image 架構不匹配，容器啟動後立即崩潰重啟。

**修正動作**：
1. 立即把兩台的 `.env`（`AGENT_IMAGE`）與 `docker-compose.yml`（`AGENT_VERSION`）都改回 0.2.10、`docker compose up -d guidant-ai-agent` 回滾，確認服務恢復健康
2. 用 `docker rmi` 刪掉錯誤平台的本地 image，重新以 `DOCKER_BUILDKIT=1 docker build --platform linux/amd64 --secret id=nexus_auth,src=.secrets/nexus.env -t guidant-ai-agent:0.2.11 --load .` 明確指定平台重 build
3. `docker inspect guidant-ai-agent:0.2.11 --format '{{.Os}}/{{.Architecture}}'` 確認回傳 `linux/amd64` 才出貨
4. 重新 `docker save | ssh jedi@<host> docker load` → 改 config → `docker compose up -d guidant-ai-agent` → 這次正常啟動、心跳成功

**教訓**：以後任何一次 agent image build，**只要開發機跟目標主機架構不同（現在是 Mac→Linux amd64），一律要帶 `--platform linux/amd64`**，`rebuild.sh` 目前沒有內建這個保護，是隱性風險（見 §10 待辦）。

### 2.3 `rebuild.sh` 在本機 bash 3.2 下會噴 `unbound variable`

`rebuild.sh` 內的中文全形註解（`（...）`）緊貼變數名 `$SCRIPT_DIR` 時，macOS 內建 bash 3.2 對 multibyte 字元邊界解析有 bug，會誤判成 `SCRIPT_DIR<垃圾bytes>` 未定義變數而中止。**繞過方法**：不要跑 `./rebuild.sh`，直接照腳本內容手動執行 `DOCKER_BUILDKIT=1 docker build --secret id=nexus_auth,src=.secrets/nexus.env -t <tag> .`（本次額外加 `--platform linux/amd64 --load`）。這不是 script 邏輯錯，是本機殼層版本問題，換一台新版 bash 的機器應該不會發生——**不建議動 `rebuild.sh` 本身**（其他人的機器可能沒事），下一棒若也遇到同樣報錯，直接繞過即可，不用花時間修腳本。

### 2.4 部署機 compose 的 `AGENT_VERSION` 是第六處版號同步點

repo 內版號同步五處（`pyproject.toml` / `config/config.py` 預設 / `rebuild.sh` 範例 / `deploy/docker-compose.yml` 的 image 與 `AGENT_VERSION`）之外，**部署機本地的 `docker-compose.yml`**（`/opt/evidence-agent/deploy/docker-compose.yml`）裡的 `AGENT_VERSION: "0.2.10"` 是獨立第六處，不會隨 git pull 自動更新（那份是部署機的本地檔案，非直接對應 repo 版控檔案，需 rsync/scp 或手動 sed 更新）。本棒兩台都已手動同步到 0.2.11，若未來再升版忘了這步，agent 回報的版本號會跟實際 image 對不上（不影響功能，但排查時會誤導）。

## §3 三 repo 改動總覽（本棒 + 前棒累積，供快速對照）

### BE（compliance-manager-be）

| Commit | 內容 |
|--------|------|
| `768aa289` | T-1.1 migration：seed openscap（SSH 型態，第4筆）+ config/param schema + setup_guide |
| `de979c30` | 補 setup_guide 欄位落地鏈路（ORM model→domain entity→mapper→serializer，migration 有加但程式碼沒接的孤兒欄位） |
| `3e30d99d` | 修正 password/private_key required 語意（條件必填，非永遠非必填） |
| `c20b22a2` | T-3.2 多檔證據回收鏈 BE 端 |
| `ab7a31b6`/`8c56dc20`/`632f6a6a`/`5f5d50c8` | 執行歷史補人事時地物 + detection_tool_name + 修 detection_tool_id 漏寫 + CM-952 多檔報告清單 |
| `0ed638a7` | **本棒**：SPEC 三頁（`tool-plugin-manage.md`/`project-task-edit.md`/`my-tasks.md`）+ FR-056 使用手冊擴充 OpenSCAP/SSH 說明 |

migration 檔（`scripts/sql/`）：`2026-07-28-fr057-1-openscap-seed.sql`、`2026-07-28-fr057-1-fix-openscap-required-flags.sql`——**三環境（DEV/STG/POC）皆已套用驗證**，`schema_migrations` 三環境比對過無落差。

### FE（compliance-manager-fe）

| Commit | 內容 |
|--------|------|
| `d3dc91a` | T-1.2 設定頁欄位型態擴充（textarea/select/boolean/condition + setup_guide 渲染+複製腳本） |
| `e77d303` | T-1.3 任務參數 select_or_text |
| `fefd27e`/`8851191` | 檢測參數顯示人看得懂的名稱 / 設定區精簡 |
| `d2599c3` | CM-952 多台掃描結果完整呈現（報告逐份可取、漏掃現形、發現數標台數） |
| `a1b49e7` | CM-954 執行歷史標示「無實質檢查」 |
| `0fc8f17` | **本棒**：重新整理執行紀錄時一併刷新證據清單（user 臨時反映的體驗問題，非正式子任務） |

### evidence-agent

| Commit | 內容 |
|--------|------|
| `2ec3c5b`/`21e157b`/`b628b1c` | T-2.1~2.3：Dockerfile + factory 註冊 + connector 骨架 + `run()` + `probe()` |
| `6cf374a` | T-2.2-fix：遠端報告暫存改家目錄（`/tmp`+sudo 在 Ubuntu protected_regular 下必炸） |
| `a14ab28` | T-3.1 多檔證據回收鏈 agent 端 |
| `c46aeeb` | bump 0.2.9 |
| `4553e86` | CM-952：漏掃不再靜默——失敗台併入 summary + bump 0.2.10 |
| `722e25c` | **本棒**：CM-954 content 對不上 OS 不再產出假成功報告 + bump 0.2.11 |

## §4 Pre-flight（下一棒接手先跑，確認現況與本文一致）

```bash
# ① 三 repo branch / working tree / HEAD 對照
for repo in compliance-manager-be compliance-manager-fe evidence-agent; do
  echo "=== $repo ==="
  cd ~/Projects/Billows/Audit-Manager/$repo
  git rev-parse --abbrev-ref HEAD
  git status --short | grep -v "^??" | head -5   # 只看有無非-untracked 的異動
  git log -1 --format="%H %s"
done

# ② agent 測試（必須帶 PYTHONPATH=.，repo 缺 conftest.py）
cd ~/Projects/Billows/Audit-Manager/evidence-agent
PYTHONPATH=. poetry run pytest test/ -q
# 預期：150 passed, 1 skipped

# ③ 122/123 agent 健康狀態
for h in 192.168.50.123 192.168.50.122; do
  echo "=== $h ==="
  ssh jedi@$h "docker ps --filter name=guidant-ai-agent --format '{{.Names}}\t{{.Image}}\t{{.Status}}'"
  ssh jedi@$h "docker logs deploy-guidant-ai-agent-1 --tail 5"
done
# 預期：guidant-ai-agent:0.2.11，Up，log 有 heartbeat 200 OK

# ④ DEV DB openscap seed 現況
psql -h 192.168.50.188 -p 25432 -U cmmgr -d guidant_ai_dev \
  -c "SELECT id,code,connection_type,status FROM config.detection_tools ORDER BY id"
# 預期：4 | openscap | SSH | available
```

## §5 下一棒可能的工作方向（視 user 下一句話決定，不要自己猜）

1. **user 手測 CM-952/954 回報問題** → 走 debugging skill，root cause 定位在 agent connector（`core/task_executor_connectors/openscap.py`）或 FE `JobExecutionDrawer.vue` 呈現邏輯，兩邊都已有詳細註解可查
2. **user 下令走完整收尾** → 讀本檔案頭「closing-and-handoff」skill 的完整流程：Notion 母案（CM-938/939/940/941）狀態同步、SUMMARY 文件、memory feedback 沉澱（§2.2 跨平台 build 教訓值得記一條）
3. **user 決定 CM-953（Windows 支援）方向** → 那是全新方案討論，不是本 arc 延伸，另開 session/FR 處理
4. **user 要求把「重新整理連動證據」（`0fc8f17`）補一張 Notion 卡** → 屬於輕量收尾動作，可以做

## §6 行為規範提醒

- **不切 branch**（三個 repo 都已在 `feature/instance-agent`，branch 不對停下問 user）
- **不自動 push**（雖然本棒三 repo 都已 push，但那是因為分別經 subagent/使用者確認過；未來新 commit 一樣要等 user 明示才 push）
- **顯式 `git add <檔名>`，禁用 `-am`**
- **憑證絕不進版控**：私鑰、DB 密碼、SSH 密碼、Nexus 帳密一律「查 `.env` / 部署文件」
- **改 agent code 要 rebuild image 才生效**（且跨平台部署必帶 `--platform linux/amd64`，見 §2.2）；改 BE service code 要重啟 BE（Claude 負責重啟，FE 由 user 自理）；部署到遠端主機（122/123）屬影響共享服務的操作，動手前務必先跟 user 確認一次（本棒有先問過才動）
- **BE 出錯先看 log**：`tail -200 log/app.log | grep -A 30 -i 'openscap\|detection\|Traceback\|ERROR'`，不先問 user
- **收尾等命令**：本棒只做了「部署 + 修 bug」不是正式收尾——Notion 母案狀態、SUMMARY、memory 都沒動，等 user 明確下令才做

## §7 不在本棒 scope（未來才做）

- CM-953（Windows/異質 OS 支援）——待 user 拍板是否開獨立 FR
- install.sh 安裝精靈（user 明示最後再做）
- `rebuild.sh` 的 bash 3.2 相容性修正 / 內建 `--platform` 保護（§2.2/§2.3 提到的隱性風險，未正式列成任務，下一棒可視情況主動提出但不要未經同意就動 script）
- agent repo 補 `pytest.ini`/`conftest.py`（跑測試需 `PYTHONPATH=.` 的既有已知小問題，非本次範圍）

## §8 給 fresh session 的超短 prompt

```
請讀 ~/Projects/Billows/Audit-Manager/compliance-manager-be/docs/features/FR-057-2607-openscap-ssh-connector/handoff/2026-07-29-fr057-arc-complete-handoff.md，
先過「🧭 原始需求」與 §0 冷接自檢（答不出先回去讀 design.md §1-§2），
再讀 §1（現況全貌）、§2（本棒踩過的坑，尤其 §2.2 跨平台 build 陷阱）、§4 pre-flight。
FR-057 三 repo 全部完成、已 push、agent 0.2.11 已部署到 122/123 兩台且健康。
等我告訴你下一步要做什麼（可能是複測回報問題、可能是正式收尾、可能是 CM-953 方向討論）。
不做收尾（Notion 母案狀態/SUMMARY/memory）除非我明確下令；不 push、不切 branch；
動遠端主機服務前先跟我確認一次。
```

---

# 📌 §9 主導 session 覆核與補充（2026-07-29 晚，另一 session 追加）

> 本節由**主導 session**（負責手測驗收與環境建置的那條線）在讀完上文後補上。上文由收口 session 撰寫，內容紮實但有兩處與事實不符、且缺少目標主機擴充的紀錄。**以本節為準**。

## 9.1 ⚠️ 修正上文 §1.1 的事實錯誤

上文表格宣稱「三 repo 全部⋯⋯已 push」，實查（2026-07-29 晚）：

| Repo | 實際 HEAD | push 狀態 |
|------|-----------|-----------|
| compliance-manager-be | `cdc10a18` docs(fr057): 全案完成換 session handoff | **ahead=1，未 push** |
| compliance-manager-fe | `0fc8f17` | 已 push（ahead=0）✅ |
| evidence-agent | `722e25c` | 已 push（ahead=0）✅ |

**未 push 的正是上文那份 handoff 文件本身**（它的 commit message 宣稱「三 repo 已 push」，但寫這句話的 commit 自己還沒 push）。不是錯誤操作——本專案規範 push 一律等 user 明示——但下一棒別被文中敘述誤導，接手時**務必自行跑 `git rev-list --count @{u}..HEAD` 確認**，不要照抄文件的宣稱。

BE working tree 另有 `CLAUDE.md` 被修改（未 commit），與 FR-057 無關，同樣不歸本 arc 管。

## 9.2 CM-954 獨立抽查結果（非採信自報）

CM-954 由另一 session 實作（agent `722e25c` + FE `a1b49e7`），主導 session 獨立驗證：**實作品質良好，且在幾個取捨上比原開卡建議更嚴謹**。

**實地重現**（121 / Ubuntu 26.04 用 2404 content 掃）：`exit=0`、405 條規則全 `notapplicable`，與開卡時證據一致。

**用該真實統計餵判定函式**：

| 情境 | pass/fail/notapplicable | `_is_content_mismatch_summary` |
|---|---|---|
| 真實不匹配（121 實測） | 0 / 0 / 405 | `True` ✅ |
| 正常掃描 | 200 / 150 / 45 | `False` ✅ |
| 容器化僅 1 條有效 | 0 / 1 / 400 | `False` ✅ |

值得記住的設計取捨：**刻意不用「notapplicable 佔比 ≥ 95%」門檻**（開卡時我建議的），因為容器化環境本來就大量規則不適用；改用「pass + fail == 0」的硬條件，只要有一條真的跑過就不判定為不匹配。另外跨 OS 家族（`ssg-rhel9` 掃 CentOS/Rocky，業界合法用法）與自訂 tailored content 都不判定，避免誤報。agent 測試 **150 passed / 1 skipped**。

⚠️ 以上為**程式碼與邏輯層驗證**；FE 的「無實質檢查」UI 標示尚未經真人操作確認，仍待 user 手測。

## 9.3 🆕 掃描目標主機從五台擴充為七台（本節唯一新增的環境變更）

上文完全沒提這件事——**121 / 122 兩台已被加入為掃描目標**，這是本 arc 的環境現況變更：

| 目標主機 | OS | oscap | 123 的 key | 122 的 key | 備註 |
|---|---|---|---|---|---|
| .121 | Ubuntu **26.04** | 1.4.3 | ✅ | ✅ | 🆕 本次新增 |
| .122 | Ubuntu **26.04** | 1.4.3 | ✅ | ✅ | 🆕 本次新增 |
| .123 | Ubuntu **26.04** | 1.4.3 | ✅ | ✅ | 原有 |
| .151 / .171 / .188 / .189 | Ubuntu 22.04 | 1.2.17 | ✅ | ✅ | 原有 |

**做了什麼**：
1. **122 產生了自己的稽核金鑰**（`~/.ssh/openscap-audit-key`，ed25519）——與 123 的金鑰**完全獨立**，不共用私鑰。動機是租戶/環境隔離：123 是 DEV agent、122 是 STG agent，不該共用憑證
2. **兩把公鑰都 append 到全部七台**目標主機的 `audit-scan` `authorized_keys`（**append 不是覆蓋**——`authorized_keys` 天生支援多把金鑰，這才是正確的隔離做法，不是複製私鑰）
3. 121 / 122 上的 `audit-scan` 帳號 + sudoers 白名單由 **user 親自執行**（該操作需 sudo 密碼，屬憑證操作不由 Claude 代做）
4. 實測**兩台 agent 都能連上全部七台**並成功執行 `sudo /usr/bin/oscap --version`

**⚠️ 但 121/122/123 這三台 26.04 目前掃不出有效結果**：全世界都還沒有 `ssg-ubuntu2604` content（目錄只有 2204 / 2404）。行為是：
- 不指定 content → probe 明確報「缺少 SCAP content」（**這是正確行為，不是 bug**）
- 硬指定 2404 content → 就是 CM-954 那個假成功情境

**所以手測請用四台 22.04**（`.151, .171, .188, .189`），profile 建議 **CIS Level 2 Server**（實測該 content 選中 497 條規則，是所有 profile 中最完整的；Level 1 Server 395 條、STIG 229 條、standard 僅 45 條）。三台 26.04 等 CM-954 的 UI 標示驗過再說。

## 9.4 122 agent 的定位釐清（曾被誤判）

過程中一度以為 122 是「另一個租戶」，實查後確認：

- **123** → 註冊在 **DEV**（`guidant_ai_dev`），agent uid `f8136df9…`，tenant 102
- **122** → 註冊在 **STG**（`guidant_ai_stg`），agent uid `90a66fc6…`，tenant **102（同一個租戶）**

兩台是**同一租戶在不同環境**，不是不同客戶。兩台皆 0.2.11、`active`、具 `detection_scan` 能力。

⚠️ **STG 上還跑不了 OpenSCAP**：STG BE 是 **v1.10.1**（已發布版），不含 FR-057 程式碼（FR-057 全部還在 `feature/instance-agent`，未進 main、未發版）。STG 的 DB seed 有、agent 有，但 BE 沒有 → 在 STG UI 操作會走到舊程式碼。**要在 STG 驗 OpenSCAP，必須先讓 FR-057 走正常發版流程進 STG**，這是發布決策，需 user 明示。

## 9.5 SQL migration 三環境對齊狀態（已查核，無待辦）

FR-057 的兩支 migration（`2026-07-28-fr057-1-openscap-seed.sql` / `…-fix-openscap-required-flags.sql`）**DEV / STG 皆已套用**（7/28 套的），STG 實查 `config.detection_tools` 有 `4 | openscap | SSH | available`，與 DEV 完全一致（id=4 這點關鍵——agent factory `_TOOL_ID_TO_CODE` 是固定映射）。

三方 diff 唯一落差是各環境專用的 cleanup 腳本（`…-DEV-cleanup.sql` / `…-STG-cleanup.sql`），設計如此不是落差。

**🔴 但查到一個與 FR-057 無關的既有落差，值得記著**：POC（`guidant_ai_poc` @ 192.168.50.189）**缺 `2026-07-07-fr048-phase4a-capability-seed.sql`**。這不是環境專用腳本，是 FR-048 統一授權守門的 capability seed，POC 沒套可能導致 `@require_capability` 換裝過的端點擋掉正常操作。**未處理，待 user 裁示**。

## 9.6 Notion 卡狀態已同步（本節作者做的）

- **CM-950**（T-2.2-fix mktemp）：`In progress` → **修正待驗證** + 完成日期 2026-07-29
- **CM-951**（T-2.3-fix probe host）：`In progress` → **修正待驗證** + 完成日期 2026-07-29

  （兩張都早已修完並經獨立抽查，狀態一直沒同步）
- **CM-954**：補上主導 session 的獨立抽查結果（含上表的三組驗證數據）

母案 CM-938 與子需求卡 CM-939/940/941 維持 `Not started` — **照規範收線時才動，等 user 下令**。

## 9.7 對下一棒的補充提醒

1. **接手先自驗 push 狀態**，別信任何 handoff（含本節）的宣稱——`git rev-list --count @{u}..HEAD`
2. **手測請用四台 22.04**，別放 26.04 那三台進去（見 §9.3）
3. **STG 驗不了 OpenSCAP**（見 §9.4），別浪費時間試
4. 若 user 要在 STG 或 POC 驗，先問清楚是否要走發版流程
5. POC 的 FR-048 落差（§9.5）如果 user 問起，資料在這裡
