# FR-056 人工手測中繼交接 — Context 已滿，接手繼續帶 user 手測

> ✓ ARC CLOSED — 2026-07-27 收尾，見 [`2026-07-27-fr056-manual-test-arc-SUMMARY.md`](2026-07-27-fr056-manual-test-arc-SUMMARY.md)。user 手測全數驗收通過，收尾工作包（CM-935：STG migration / 使用手冊正式化 / SPEC 更新 / 本 SUMMARY）已完成。本文件保留作歷史交接紀錄，行為描述請以 SUMMARY 與最新 SPEC/使用手冊為準。

| 項目 | 內容 |
|------|------|
| 緣由 | 主導 session（首腦角色：分析 + 派 case 給 runner + 跟 user 一起手動驗證）context 已滿，中繼交接 |
| Branch（三 repo 同名） | `feature/scan-plugin-integration`（**不可切 branch**） |
| 角色 | 你是首腦：分析 + 派 case 給 runner + 跟 user 一起手動驗證全部功能，**不自己實作** |
| 現況一句話 | 端到端掃描鏈路已跑通（多輪 bug 修復後），目前 **6 張 case 等 user 手測驗收**（927 主戰場 + 930/931/932/933/934 子修正），Notion 狀態有落差需先核實 |
| push 狀態 | 三 repo 皆有未 push commits（push 永遠等 user 明示，**尚未 push**） |
| 預估時間 | 手測本身無法預估（等真實 OpenVAS 掃描，每輪 15~20 分鐘）；交接閱讀 15 分鐘 |

## 🧭 原始需求 / WHY（先讀這段，別跳過）

FR-056 讓客戶「檢測工具掃描 → 報告自動變任務證據 → 通知 → 完成」全自動化。四子需求 56.1（工具設定）/ 56.2（任務類型）/ 56.3（Agent 執行）/ 56.4（執行編排+轉證據）程式碼審查已放行，但**真實 OpenVAS 端到端掃描一直沒做過**（CM-927）。本棒（一整天）就是在做這件事：跟 user 一起在 DEV 環境對真實 OpenVAS（部署在 123 = ubuntu-lab-03）跑真掃描，**過程中連續挖出 10 個先前程式審查沒抓到的 bug**（見下方「本棒完整戰史」），每個都開 Notion case 派給 runner 修、驗收、重部署、再測，滾動式推進。

**現在的狀態**：核心鏈路（測試連線 → 任務設定 → 開始執行 → agent 領工 → OpenVAS 真掃描 → 報告回收 → 證據入庫 → 通知信 → manual 手動完成）**已經完整跑通一次成功**（15:02~15:20，152 掃描 succeeded，PDF 證據 + summary 統計都有）。後續又追加了「取消機制」「命名撞名」「篩選連動」「UI 收合」等 4 個子修正（930/931/932/933/934），**全部程式碼已 commit，但只有部分實測驗證過**。

**你接手的任務**：
1. 先核實 Notion 卡片狀態與 git commits 是否一致（見 §7，有落差）
2. 帶 user 把剩下的手測項目跑完（PDF 證據、取消機制、命名撞名、auto 模式、失敗情境 — 見 §4 開工順位）
3. 手測全過後，**等 user 明確下收尾令**才做 spec / SUMMARY / 母案收口 / memory（不要自己接著跑）

## 🧭 冷接自檢（讀完 §0~§3 後自問，答不出來回去讀）

1. 為什麼要做這一整輪手測？（提示：56.1~56.4 只過了程式審查，從沒對真實 OpenVAS 跑過）
2. 目前端到端鏈路的「已知良好基準」是哪一次掃描？（提示：exec id=5，15:02~15:20，succeeded）
3. 現在還沒驗證過的是哪些？（提示：932 的 PDF/summary 實測、931 的取消確認框實測、934 的撞名修正實測、auto 模式、失敗情境）
4. 為什麼 Notion 卡片狀態不能直接信？（提示：930/931/934 我已程式驗收但卡片還顯示 Not started，需要你重新核實或提醒 user）
5. 為什麼「重新執行」按鈕現在會彈確認框？（提示：931 修正，掃描中重按會先真中斷 OpenVAS 側 stop_task 才派新工單，避免並行掃描疊出孤兒 task）

---

## §0 接手讀序

**🔒 先讀（懂 WHY，不可跳）**：
1. 本文件全文（尤其 §1 現況戰況表 + §4 開工順位）
2. `docs/features/FR-056-2607-detection-tool-integration/handoff/2026-07-27-fr0565-probe-and-e2e-handoff.md` — 更早一棒的交接，含 FR-056.5 probe 設計決策全文（案 1 雲端直推 vs 任務化的取捨）

**接著讀（機械座標，開工前查）**：
3. §7「Notion 座標與狀態核實」— 六張卡的 page id + 當前落差
4. §5「三 repo 版號與部署現況」
5. §8「行為規範重要提醒」

**冷接自檢**：讀完能答出上面 5 題才開始碰任何操作。

---

## §1 現況戰況表（本棒完整戰史，10 個 bug 修復鏈）

user 手測時我們（主導 session）連續發現、開 case、派 runner 修、驗收、重部署的完整鏈路，**依發現順序**：

| # | Case | 問題 | 修法 | 狀態 |
|---|------|------|------|------|
| 1 | CM-929（FR-056.5） | 測試連線用 BE httpx 直連 OpenVAS，架構死（BE 連不到客戶內網） | 改「雲端直推」：BE mTLS POST agent `/detection/probe`，agent 用 python-gvm 探測 | ✅ 已驗收，Notion=修正待驗證 |
| 2 | （同案追加，未單開）| 派工 `tenant_config_id` 從未寫入 → 憑證永遠解不到 | fallback 用 `(tenant_id, detection_tool_id)` 反查 config | ✅ 已驗收（commit a0d593ab） |
| 3 | （同案追加）| 心跳 API log 記錄明文憑證，違反 D9 | api_log middleware 對 secret 類 key 通用遮罩 | ✅ 已驗收（commit e2eb1c2c） |
| 4 | （同案追加）| 規劃頁「開始執行任務」不會自動派 detection 任務首次掃描 | `start_task_execution` 尾端加自動派工（user 拍板：自動化是核心價值） | ✅ 已驗收（commit 538d8da0） |
| 5 | （同案追加）| agent 心跳解析錯信封層級，`pending_tasks` 永遠讀不到 | `body.get("data", body)` 容錯（真根因，堵死真實掃描） | ✅ 已驗收（agent commit f1b6629） |
| 6 | （同案追加）| `create_target` 缺 `port_list_id`，GVMd 400 | 補預設 port list UUID + params 可覆寫 | ✅ 已驗收（agent commit 3515320） |
| 7 | （同案追加）| hosts 是字串被當 list，逐字元拆解成垃圾 | connector 邊界正規化為 list | ✅ 已驗收（agent commit cdd76e8） |
| 8 | （同案追加）| 心跳「先等滿一輪才第一跳」，升級部署要空等 | 改「先跳再等」 | ✅ 已驗收（agent commit e8f667f） |
| — | **端到端掃描第一次成功** | — | exec id=5，15:02:09→15:20:25，152 掃描 succeeded，PDF 證據入庫 | ✅ **已達成，是後續驗收基準** |
| 9 | CM-930 | 任務抽屜「執行紀錄」一律全展開，多筆時佔位 | 加可收合 toggle + 智慧預設展開（running/failed 才展開）+ 區塊滾動 + BE 排序移到 repo 層 | ✅ 已驗收，**Notion 卡仍顯示 Not started（落差，見 §7）** |
| 10 | CM-931 | 「重新執行」無確認框，掃描中按會疊出並行掃描 | user 拍板方案 C 真中斷：確認框 → agent `/detection/cancel` → `gmp.stop_task()` 真停 → 才派新工單；競合防護（取消後舊掃描若仍回報，不轉證據/不通知/不觸發 auto） | ✅ **程式已驗收**，**尚未實測**（見 §4） |
| 11 | CM-932 | 報告存 XML 使用者看不懂；`summary` 永遠空 | 同一 report_id 取 PDF（證據）+ XML（解析 `<result_count>` 填 summary，不上傳） | ✅ 程式已驗收，Notion=修正待驗證，**尚未實測**（見 §4） |
| 12 | CM-933 | `/project/task-manage` 輪次篩選與專案篩選不連動 | 未選專案 disabled；選定後改拉該專案完整輪次清單（改走既有 audit-rounds/list API） | ✅ 已驗收，Notion=修正待驗證 |
| 13 | CM-934 | 同批發佈多個同目標任務會撞名（`Target exists already`） | `create_target`/`create_task` 命名從秒級 timestamp 改用 agent task_uid（天然唯一） | ✅ **程式已驗收**，**Notion 卡仍顯示 Not started（落差）**，**尚未實測**（見 §4） |

**版號軌跡**（evidence-agent，三輪疊加後最新）：0.2.5（CM-929 鏈）→ 0.2.6（CM-932 PDF）→ 0.2.7（CM-931 取消）→ **0.2.8（CM-934 撞名，目前部署版本）**。BE/FE 無版號概念，看 commit hash。

**額外開的 case（尚未派工）**：
- 檔案裡沒開卡，但 §1 之外還討論過「agent 對外暴露安全性」（弱掃背景雜訊打到 agent port，可能需要防火牆收緊）— **未開 case，未派工**，交給下一棒判斷是否要開。

---

## §2 前次教訓（別重蹈覆轍）

1. **agent 心跳間隔優先讀部署機 `certs/agent.json` 快取，不是環境變數** — 改 `.env`/compose 的 `HEARTBEAT_INTERVAL_SEC` 對已註冊的 agent 完全無效，已存 memory `reference_agent_heartbeat_interval_cache.md`。要改要嘛改快取檔（`sed` 後 restart），要嘛重新註冊。
2. **`docker compose up -d` 不帶 service 名會 recreate 整個 compose 的所有服務**（含 DB）— 已存 memory `feedback_compose_up_scope_service_name.md`。永遠 `docker compose --profile full up -d guidant-ai-agent`，不要裸 `up -d`。
3. **agent 版號 bump 有五處要同步**（`pyproject.toml` / `config/config.py` AGENT_VERSION 預設 / `deploy/docker-compose.yml` image tag + AGENT_VERSION env / `deploy/.env.example` / `rebuild.sh` 註解）— runner 連續三輪（0.2.6/0.2.7/0.2.8）都只改了 pyproject，其餘四處停在 0.2.5，我已手動補齊並 commit（`e59c9fc`）。**下次 bump 版號要主動核對這五處，不要只信 runner commit message 說「已同步」**。
4. **`docker compose restart` 不會重讀 compose 檔變更，要用 `up -d`** — restart 只是重開既有 container 的既有設定；改了 env 值要 `up -d` 才會偵測差異重建。
5. **心跳 response 是標準信封 `{"data": {...}, "status": true}`，agent 端解析容易忘記從 `data` 底下取值** — CM-929 鏈路裡的信封 bug 就是這樣來的，之後任何雲端→agent 回應解析都要留意這個模式。
6. **DDD 分層 + 命名唯一性這類 bug 都是「單元測試 mock 全綠、真機才炸」** — port_list_id 缺失、hosts 型別錯誤、target 撞名，三個都是這個模式。往後新 case 的驗收要求都要求「斷言實際呼叫參數」而非只驗 mock 回傳值。

---

## §3 Notion 狀態核實結果（已驗證，可直接採信）

用 Notion query 對比 Case No 927/929/930/931/932/933/934 的狀態，與我親自審過的 git commits 交叉比對：

| Case | Notion 狀態（查詢當下） | git commits 是否存在 | 我的程式驗收結論 |
|------|------------------------|----------------------|-------------------|
| 927（主戰場） | Not started | N/A（這張本來就是手測 checklist，不是修 code） | 尚有多項待手測，見 §4 |
| 929 | 修正待驗證 | ✅ 存在且已驗收 | 一致 |
| **930** | **Not started** | ✅ 存在（FE `f2ba9b7`、BE `318b9625`）且我已驗收放行 | **落差** — runner 可能沒做狀態更新，或 user 手測後才會轉 |
| **931** | **Not started** | ✅ 存在（BE `3a9a9c05`、FE `e986b88`、agent `a7bad25`）且我已程式驗收放行 | **落差** — 尚未實測，狀態未轉「修正待驗證」正常，但也可能是 runner 漏更新 |
| 932 | 修正待驗證 | ✅ 存在（agent `60ad41f`、BE `5c0ba4da`）且我已驗收放行 | 一致，等實測 |
| 933 | 修正待驗證 | ✅ 存在（FE `da4b422` + `6febb2b`）且我已驗收放行 | 一致 |
| **934** | **Not started** | ✅ 存在（agent `703b59a`）且我已程式驗收放行 | **落差** — runner 可能沒做狀態更新 |

**下一棒動作**：不要假設 Notion 狀態準確。930/934 你可以直接信我的驗收結論（已放行，等 user 實測），不用重查 diff。931 同樣已放行，只是還沒實測過（跟狀態落差無關，是正常流程）。**建議接手後把 930/934 的 Notion 狀態手動改成「修正待驗證」**（除非你重新核實後發現有問題）。

---

## §4 開工順位（手測劇本，依優先序）

user 目前在「人工測試中」——這是你接手後要立刻帶 user 做的事，不是自己寫 code。

### Step 1：核實環境活著（30 秒）

```bash
# BE 進程存活 + 是最新 commit 跑的（重啟時間需晚於 3a9a9c05 這個 commit 的時間）
ps aux | grep main_app.py | grep -v grep

# agent 版號（應為 0.2.8，last_seen 應在最近 5 分鐘內）
cd ~/Projects/Billows/Audit-Manager/compliance-manager-be
export PGPASSWORD=$(grep '^#DB_SECRET' .env | sed 's/^#DB_SECRET=//' | python3 -c "import json,sys; print(json.loads(sys.stdin.read())['rds_master_password'])")
psql -h 192.168.50.188 -p 25432 -U cmmgr -d guidant_ai_dev -t -A \
  -c "SELECT 'agent version=' || agent_version || ' last_seen=' || to_char(last_seen_at,'HH24:MI:SS') || ' now=' || to_char(now(),'HH24:MI:SS') FROM compliance.remote_agents WHERE id=8;"
```

若 agent last_seen 超過 5 分鐘沒動、或版號不是 0.2.8 → 先跟 user 確認 123 上的 container 是否還活著（`docker compose --profile full ps`），不要跳過這步直接測。

### Step 2：CM-932 實測（PDF + summary）— 建議優先，因為順便驗證整條鏈路還通

帶 user 對已知的 detection 任務（job 13342 或 13362，兩個都是 manual 模式、hosts=151，目前都 PROCESSING）到抽屜按「重新執行」（此時無 running 執行，不會彈確認框，直接派工）。

驗收重點：
- 掃完後證據列表出現的是 **PDF**（不是 XML），檔名格式 `OpenVAS掃描報告_192.168.50.151_<日期>.pdf`
- 抽屜「發現 N 項」有真實數字（不是空白）
- 下載 PDF 能直接開，內容是 Greenbone 排版報告

### Step 3：CM-931 實測（取消機制）— 依賴 Step 2 的掃描還在跑時操作

**這步要抓時機**：Step 2 的掃描開始後（狀態變 running，約派工後 1~2 分鐘），**趁它還在跑**再按一次「重新執行」。

驗收重點：
- 應彈出確認框（文案「上一次執行將被中止」類）
- 確認後開 Greenbone UI（`https://192.168.50.123:9392` → Scans → Tasks）看**舊 task 變 Stopped**、**新 task 開跑**
- 抽屜執行歷史：舊那筆狀態變「已取消」（cancelled，灰色 Tag）、新的一筆 running
- 若不小心錯過時機（掃描已經 succeeded 才按）→ 不會彈框（無 running 執行），這是正常行為，重跑一次抓時機即可

若 agent 端 `/detection/cancel` 呼叫失敗（agent 離線等）→ 應該回 409，**不能默默派出新工單**，這是 §1 表格裡強調過的關鍵行為，務必驗證到。

### Step 4：CM-934 實測（撞名）

到規劃頁，**同一批發佈兩個以上**同目標（hosts=151）的 detection_tool 任務（可以用不同 completion_mode，一個 manual 一個 auto，順便驗 Step 5）。

驗收重點：
- 兩個任務都能成功派工、成功建立各自的 target/task（不再出現 `Target exists already`）
- Greenbone UI 上兩個 target 名稱不同（後綴應為各自的 task_uid 前 8 碼）

### Step 5：auto 模式驗收（CM-927 原始 checklist 未勾項目）

Step 4 若有建 auto 模式的任務 → 掃完應**自動變 COMPLETED**（不用手動按完成）。若還沒測過，額外建一個 auto 任務單獨測。

### Step 6：失敗情境驗收（CM-927 原始 checklist 未勾項目）

建一個 hosts 填不存在 IP（如 `192.168.50.199`）的任務 → 執行應標「失敗」、錯誤訊息可辨識（網路不可達類訊息，非籠統錯誤）、任務仍留 PROCESSING 可從抽屜重試。

### Step 7：CM-933 快速複驗（純 FE，5 秒可驗）

到 `/project/task-manage`：專案篩選=全部時輪次應 disabled；選定專案後輪次只列該專案的；切換專案輪次自動 reset。

---

## §5 三 repo 版號與部署現況

| Repo | 目前 commit（HEAD） | 版本 | 部署狀態 |
|------|---------------------|------|----------|
| compliance-manager-be | `3a9a9c05` | N/A | 本機 `python main_app.py` 跑著（PID 34101，2026-07-27 17:41 起，含 CM-931 的取消機制） |
| compliance-manager-fe | `e986b88` | N/A | Vite dev server HMR，`localhost:5180`，改檔即生效 |
| evidence-agent | `e59c9fc`（含 CM-932/931/934 + 版號補齊） | **0.2.8** | 已部署到 123（`ubuntu-lab-03`），雲端 DB 確認 `agent_version=0.2.8`、`status=active` |

**working tree 全乾淨**（三 repo 皆無未 commit 改動，`git status --short` 已核實）。

**push 狀態**：三 repo 都有一長串未 push commits，**push 永遠等 user 明示**，不要自動 push。

---

## §6 DB 現況快照（供比對，勿當唯一真相，重新查一次更保險）

```
compliance.remote_agents (id=8)：agent_version=0.2.8, status=active, last_seen=17:54:41

compliance.detection_executions（最新 5 筆）：
  id=8  failed     job=89a11a15... (13342) started=15:52:43
  id=7  succeeded  job=7232a47e... (跟哪個 job 對應需查) started=15:47:46
  id=6  failed     job=89a11a15... (13342) started=15:47:46
  id=5  succeeded  job=d0dac9be... (13362) started=15:02:09  ← 端到端第一次成功基準
  id=4  failed     job=d0dac9be... (13362) started=14:52:50

compliance.job_executions：
  id=13342, uid=77a9079c-..., status=PROCESSING（detection_tool, manual）
  id=13362, uid=d0dac9be-..., status=PROCESSING（detection_tool, manual）
```

exec id=6/7/8 是後續（CM-932/CM-934 修正過程中）的測試紀錄，其中有失敗的（可能是撞名問題被抓到的證據，或 CM-934 修好前的殘留失敗）。**不要假設這些是「新 bug」**，先看 error_message 判斷是否是已知已修的問題。

```sql
SELECT id, status, error_message FROM compliance.detection_executions WHERE id IN (6,7,8);
```

---

## §7 Notion 座標

- 母案 CM-907：`3a9346da-4cd0-81a5-be6f-f0ddd6d770c6`
- 任務清單 data source：`collection://23c346da-4cd0-8041-955e-000bb6976dd2`
- CM-927（主戰場手測 checklist）：`3aa346da-4cd0-81f9-a029-deda20be47cd`
- CM-929（FR-056.5 probe）：`3aa346da-4cd0-8191-9fba-c4fb2474820f`（狀態=修正待驗證）
- CM-930（執行紀錄可收合）：`3aa346da-4cd0-81f6-bfa6-e890f17e0f60`（**狀態顯示 Not started，實為已驗收**）
- CM-931（取消機制）：`3aa346da-4cd0-81cc-934a-f1585aacf6f9`（狀態=Not started，正常，尚未實測）
- CM-932（PDF+summary）：`3aa346da-4cd0-8113-b184-d7596efc3602`（狀態=修正待驗證）
- CM-933（輪次篩選連動）：`3aa346da-4cd0-8149-a35a-cb7cbf94e715`（狀態=修正待驗證）
- CM-934（撞名）：`3aa346da-4cd0-8125-bcd4-e7333cc1bab8`（**狀態顯示 Not started，實為已驗收**）

DEV DB：`psql -h 192.168.50.188 -p 25432 -U cmmgr -d guidant_ai_dev`（密碼查 BE `.env` 註解行 `#DB_SECRET`，用 `cmmgr` 帳號那組）

BE 起服務 `python main_app.py`（port 8000），**改 service 要 kill -9 重啟**；log 在 `log/app.log`

FE dev server 在 5180（HMR，改檔即生效）

Agent 部署機：`jedi@192.168.50.123`（ubuntu-lab-03），deploy 目錄 `/opt/evidence-agent/deploy`，SSH key 已加（雙方都可連）

---

## §8 行為規範重要提醒

- **不切 branch**，三 repo 都在 `feature/scan-plugin-integration` 工作
- **push 永遠等 user 明示**，不自動 push
- **收尾（spec / SUMMARY / 母案收口 / memory）等 user 明確下令才做** — 手測全過不代表可以自動跑收尾流程
- **派 subagent 一律用 1M context model**（不帶 model override，繼承主 session）— 今天多次因用 sonnet 導致 context 爆炸重派，這條鐵律要嚴守
- 繁體中文；Notion 先搜尋再開卡（今天開的 6 張新卡都先確認過無重複）；Claude/runner 做的作業人員填「小弟」
- BE 改 service 要 **kill -9** 重啟（`ps aux | grep main_app.py` 找 PID）
- Agent 每次改完要 **rebuild + docker save/load 出貨到 123**，且 `docker compose --profile full up -d guidant-ai-agent`（**必須帶 service 名**，見 §2 教訓 2）
- 密碼/憑證類資訊絕不代打、絕不寫入任何會 commit 的檔案（今天 user 曾在對話中貼過 123 的 SSH 密碼，已提醒但沒代打，也沒有寫入任何檔案）

---

## §9 不在本期 scope

- OpenVAS target/task 的**清理策略**（每次掃描都新建，殘留物正在累積）— CM-934 卡內已提及但明確標「本次不實作」，若 user 想處理需另開 case
- agent 對外暴露的**安全性強化**（防火牆規則、只放行雲端來源 IP）— 只在對話中口頭提過，**未開 case**，需要 user 決定優先度
- Nessus / SonarQube 等其他檢測工具的 connector 實作 — 平台預留但本輪全程只測 OpenVAS
- STG / POC 環境的 migration 套用（CM-932 的 param schema migration `2026-07-27-fr056-5-openvas-param-schema-port-list.sql` 只套了 DEV）

---

## §10 給下一棒的超短 Prompt（可直接複製貼開新 session）

```
請讀 docs/features/FR-056-2607-detection-tool-integration/handoff/2026-07-27-fr056-manual-test-mid-arc-handoff.md
接手 FR-056 主導 session。角色是首腦：分析 + 派 case 給 runner + 跟 user 一起手動驗證
全部功能，不自己實作。

先過交接文件的「🧭 原始需求 / WHY」+「冷接自檢」5 題（答不出來回去讀 §1 戰況表）。

現況一句話：端到端掃描鏈路已跑通（10 個 bug 修復鏈後），CM-930/931/932/933/934 五張
子修正 case 程式碼已驗收完成，正在等 user 手動實測。§4 開工順位是接下來要跟 user
一起做的手測劇本，照順序帶 user 測（PDF+summary → 取消機制 → 撞名 → auto 模式 →
失敗情境 → 篩選連動複驗）。

§3 有 Notion 卡狀態核實結果（930/934 卡片顯示 Not started 但實際已驗收，屬已知落差，
不用重查 diff，直接信這份交接文件）。

Pre-flight：先跑 §5 的 repo 狀態核對 + §6 的 DB 快照重查一次，確認環境沒有在你離開
期間被變動過，再開始帶手測。
```
