# FR-060 檢測基準內容管理 — LOG（append-only，每棒追加一 block）

> **這是 append-only 檔。既有 block 一律不改。** 發現舊 block 有誤 → 在新 block 的「推翻了什麼」欄寫明更正。
> 現況請看 `fr060-STATE.md`（living）。

---

## 第 1 棒 — 2026-08-03（討論 → 設計定案）

**做了什麼**
- 走 `big-feature-workflow`：Explore 探脈 → HTML 討論稿（1,003 行、18 項 D 項 callout、4 張 mermaid）→ 決策者逐項審 → design.md 定案
- D1–D19 全數拍板；`discussion.md` / `discussion.html` / `design.md`（1030 行）三份文件產出

**commits**
- `7124a473` 討論稿補 D19 多工具擴充邊界（決策者當場定調）
- `7e3e7b97` 設計定案 design.md（D1-D19 全數拍板）+ FR 登記表

**關鍵決策**
- **D5 被決策者當場推翻**：原建議「enum 值 FE 寫死」→ 改「存 DB 由 root 維護」（原話「這類最好都要可以維護」）。連帶多出三塊必做工作（顯示名不落庫／刪除保護／維護介面），FR-060.2 範圍因此比原討論稿估的肥
- **D19 是決策者當場定調不是照建議**：原話「不能像這次一樣又大幅度更新，上線後很危險」→ 三層擴充結構，擴充點一律「加資料／加實作類別」不是「加欄位／改欄位語意」。連帶改寫 D12 欄位定義（嚴重度欄不叫 `impact`）
- **D20 多語化被決策者砍出範圍**：「我不想把需求拉複雜，名稱跟描述之後再補吧」→ 記在 design.md §6.3 免得半年後有人重新發現一次

**教訓**
- 原本以為拆表只影響管理面，**實 grep orchestration 後發現兩處會壞**，其中破口①是無聲的授權漏洞（`None is False` 為假 → 停用的 profile 照樣派得出去）。**「應該不受影響」必須 grep 驗證，不可推估**
- id 32/33 的三欄 JOIN 陷阱是**實查 DEV 資料才發現的**，而 STG 資料形態測不到它

**推翻了什麼**
- 推翻自己原本「拆表對派工鏈零影響」的判斷（§4.3 兩處破口）

---

## 第 2 棒 — 2026-08-03（Notion 建卡，未完成）

**做了什麼**
- 讀 CM-1054 母卡 + design.md §3/§4/§5/§7/§8，複驗程式碼與 DB 座標
- 建三張子需求卡：**CM-1055**（FR-060.1）／**CM-1056**（FR-060.2）／**CM-1057**（FR-060.3）
- 回填 CM-1054 母卡的「子需求卡連結」段（含待辦與座標漂移表）
- 寫本 arc 的 STATE / LOG 雙檔

**commits**
- 無（本棒只動 Notion 與交接文件，零程式碼異動）

**關鍵決策**
- 子需求卡的**子任務拆法定為每階段四塊**，寫進各卡「範圍」表格供下一棒直接建卡：
  - `.1` → T-1.1 migration ／ T-1.2 資料層 ／ T-1.3 服務與 API 讀取端 ／ T-1.4 派工鏈破口修補
  - `.2` → T-2.1 enum 表+seed+分類補登 ／ T-2.2 API（taxonomies + PUT 編輯）／ T-2.3 FE 管理頁重構 ／ T-2.4 FE 下拉分組+fallback 修補
  - `.3` → T-3.1 主機依賴 ／ T-3.2 註冊表+InSpec extractor ／ T-3.3 非同步管線 ／ T-3.4 FE 詳細頁

**教訓 / 事實更正（給下一棒）**
- 🔴 **design.md §4.3 的「三處呼叫點」是錯的，實際只有兩處**：`detection_orchestration_service.py:224`（`_load_profile`）與 `:794`（`_humanize_profile_param`）。建 T-1.4 卡時寫兩處
- 🔴 **design.md 提到的三個 FE 檔案都沒寫路徑，且不在直覺位置**：實際在 `src/views/detection-profile/`、`src/components/detection-tools/`、`src/views/device/`（詳見 STATE §6）
- DEV 13 筆資料形態已實查列在 STATE §2，下一棒不必重查

**未完成（交棒原因）**
- 本 session 反覆撞 `Response stalled mid-stream`（單次輸出過長導致串流中斷），**12 張子任務卡與三份交接 prompt 未建**
- 下一棒接續 STATE §4 的待辦 #1~#3

**推翻了什麼**
- 更正第 1 棒 design.md §4.3 的「三處」為「兩處」（見上）

---

## 第 3 棒 — 2026-08-03（建子任務卡 + T-1.1 落地）

**做了什麼**
- 建 **7 張子任務卡 CM-1060~1066**（乙案），回填四處「子任務卡連結」段，七張卡附加共通的「必讀＋作業紀律＋完成後四步」區塊，CM-1061 額外插入前置狀態段
- 發出 CM-1060（T-1.1 拆表 migration）並由協調者實查驗收通過
- 事後補 CM-1062 卡頭的「10 筆 soft-ref」事實更正，更新 STATE §2／§4／§6

**commits**
- `d7cf9abc` T-1.1 拆表 migration（CM-1060）——只新增 `scripts/sql/2026-08-03-fr060-1-detection-profile-split.sql`（662 行），零 Python 異動

**關鍵決策**
- 🔴 **子任務卡改乙案 7 張，推翻第 2 棒規劃的 12 張**：原 T 之間依賴過緊（T-1.2 與 T-1.3 必定同一 session 做完），**卡切得比執行單位細只會讓回寫時出現「一張卡改一半」**。改為卡與執行 session 一對一
- 原 **T-3.1（裝 CINC Auditor）未單獨建卡**：安裝屬環境動作、由決策者決定時機，程式碼與文件部分併入 CM-1065
- **共通紀律寫進卡片本身**（必讀清單／作業紀律／完成後四步），派工單因此縮成一行。決策者原話：「不要每次都用攏長 prompt，很浪費 token 也會斷掉」
- **DEV 階段不加相容 view**：拆表後 BE 會有一段壞掉的過渡期，決策者裁示「開發階段就是開發，直接往下做」

**T-1.1 驗收數字（DEV 實測）**
- 主檔 13／從檔 13／`current_version_id IS NOT NULL` = 12／uid 零遺失 = 0／控制項表 0 筆／`extraction_status` 全 `pending`
- id 32→tool 8、id 33→tool 4，三欄 JOIN 正確無 cross join；舊表 rename 為 `_deprecated_20260803` 未 DROP
- RLS 主從各 4 段共 8 段；`cm_app` 實測租戶 131 讀到 10 筆全 SYSTEM、對租戶 102 外洩 0 筆
- STG／POC 均未被動（`config.detection_profile%` 新表數 0／0）

**教訓**
- 🔴 **驗收只查 DB 沒起 BE，漏掉「BE 目前壞著」這件事**——`__tablename__` 仍指已 rename 的舊表，是 T-1.1 runner 自己在回寫裡揭露的，不是驗收查出來的。**拆表類任務的驗收要含「服務還起不起得來」，不能只驗資料正確**

**推翻了什麼**
- ① 推翻第 2 棒規劃的 **12 張子任務卡拆法**，改乙案 7 張（理由見上）
- ② 更正 design.md §8.1「既有 10 筆 soft-ref 引用零轉換仍可解析」的描述：**實際只有 6 筆指向 profile uid**（`tool_params` 4 筆 4/4 全對 ＋ `agent_tasks.params` 6 筆裡只有 url 型 2 筆），另 4 筆 file 型的 `_profile.uid` 指向的是 `upload_files` 的 uid、本來就不指向 profile 表。已寫進 CM-1062 卡頭與 STATE §6

---

## 第 4 棒 — 2026-08-03（七張卡執行 ＋ 手測修正 ＋ 收尾）

**做了什麼**
- 依 STATE §4 序列逐張發卡執行 CM-1061~1066，六張卡全數落地（CM-1060 於第 3 棒完成）
- 決策者手測驗收後補三支 FE 修正；本棒收尾產出 arc SUMMARY、更新 STATE、追加本 block

**commits**（**BE／FE 皆未 push**）
- BE `01d0909b` CM-1061 T-1.2+1.3 資料層／服務層改寫（38 檔，+2925/−1589）
- BE `40fcc38d` CM-1062 T-1.4 派工鏈兩處破口 ＋ 迴歸測試（2 檔，+137/−7）
- BE `a2f2512b` CM-1063 T-2.1+2.2 分類 enum 表 ＋ seed ＋ 13 筆補登 ＋ PUT 編輯 ＋ 刪除保護（22 檔，+2028）
- BE `ec4e70b7` CM-1065 T-3.2+3.3 抽取器註冊表 ＋ InSpec extractor ＋ 非同步管線（6 檔，+1170/−6）
- FE `28f061f` 補 8 個 error code i18n／`97f9ac8` CM-1064 管理頁重構（1,239→639，拆六支）／`bbcb882` CM-1066 控制項詳細頁＋摘要區＋輪詢
- FE 手測後三支：`07b8a7d` 分類欄拆三欄／`e4e7967` 中繼資料標籤中文化／`7274d13` 修多列展開只剩最後一筆有資料

**Notion**：CM-1060~1065 六張 → `修正待驗證`；CM-1066 尚未回寫；母卡 CM-1054 仍 `In progress`（收口待另行下令）

**關鍵決策**
- **抽取採非同步管線 ＋ 狀態輪詢**（`extraction_status` 落在從檔）。被排除：同步解析——CINC Auditor 解一支 700 條的 profile 是秒級以上，卡在上傳 request 裡會讓使用者以為上傳失敗
- **控制項讀取端路徑前綴用 `-versions` 不是 `-profiles`**：控制項屬於某一版而非一支基準（同支 v1／v2 內容可以完全不同），uid 收的是從檔 uid
- **手動重抽 `POST .../extraction` 對 create capability**（與版更同一組，兩者都是「產生這一版的內容」）；同路徑 `GET`（狀態輪詢）不設 capability，與其他讀取端一致

**教訓**
- 🔴 **驗收只查 DB 沒起 BE，會漏掉「服務起不起得來」**——CM-1060 完成後 BE 其實是壞的（`__tablename__` 仍指已 rename 的舊表），是 runner 自己在回寫裡揭露的，協調者的驗收沒抓到。**拆表類任務的驗收必須含「服務還活著」這一項**，不能只驗資料正確
- 🔴 **401 分不出「端點存在」與「端點不存在」**——`@jwt_required()` 在路由解析前就擋下，兩種情況都回 401。用 401 驗端點是**無效驗證**。正解是 **OPTIONS 探路由**（存在回 200 ＋ `Allow` 標頭）
- 🔴 **把共通紀律寫進卡片本身，派工單就能縮成一行**——決策者原話「不要每次都用攏長 prompt，很浪費 token 也會斷掉」。七張卡各附「必讀清單 ＋ 作業紀律 ＋ 完成後四步」後，派工單只剩「請處理 CM-10xx，照卡做」，本棒六張卡全程無一次因 prompt 過長斷流（對比第 2 棒反覆撞 `Response stalled mid-stream`）
- **PrimeVue 3 的展開列會整個銷毀重建**：`BodyRow` 用 `<component :is="templates['expansion']">`，而 `templates.expansion` 是父層插槽函式本身，父層每次 re-render 都是新實例 → `:is` 視為新元件型別 → 已展開的列全部銷毀重建。**加 `:key` 或改具名函式 ref 都擋不住**，只能讓子元件自己管載入 ＋ 模組層快取。會再遇到的框架坑

**推翻了什麼**
- ① 再次確認第 3 棒已推翻的 **12 張子任務卡拆法**——乙案 7 張（卡與執行 session 一對一）實跑無「一張卡改一半」情形，拆法定案
- ② **推翻協調者對多列展開 bug 的根因推測**：原猜是 ref 時序問題（元件 ref 在展開前尚未就緒），實際是 **PrimeVue 插槽函式 identity 每次 re-render 都變**（見上）。按原推測方向修（調 ref 時序／加 nextTick）不會有效
- ③ **更正 STATE §2 的 DEV 數字**：協調者交付的事實基準寫「控制項 942／已抽取 2 支」，收尾日實查為 **控制項 1,641／succeeded 3／failed 1／pending 9**——差異來自手測期間又觸發了一支抽取（`TWGCB-Windows-2025`，708 條），非資料異常。三環境未動的結論不變（STG／POC `config.detection_profile%` 新表數皆 0）

**留給下一棒**：全案實作完成，剩 push（BE 14／FE 6，全 branch 的事）與上版（三支 migration 只套 DEV，STG／POC 需決策者放行）。詳見 `2026-08-03-fr060-arc-SUMMARY.md`。

---

## 第 5 棒 — 2026-08-04（CM-1072 納入 ＋ 收尾文件更正）

**做了什麼**
- 更正 SUMMARY／STATE 兩份收尾文件：CM-1072 納入 commits 清單、新增 §2.4 url 型抽取（含三條不變式）、DEV 數字全面更新、Notion 卡片樹補列、新增「url 型明細會靜默偏離」follow-up
- 同 arc 另有一支 agent 更新 SPEC（`docs/specs/current/system-admin/detection-profile-manage.md`）與使用手冊，內容以程式碼為準

**commits**
- 本棒零程式碼異動（只改交接文件，由協調者統一 commit）
- 納入清單的 `25045758` `feat(FR-060.3): url 型基準支援內容抽取（BE 代下載＋SSRF 防護，CM-1072）`——4 檔：新增 `common/util/safe_http_fetch.py`（347 行，SSRF 五道防護）、改 `detection_profile_extraction_service.py`（+120）／`serializers/detection_profile.py`（+4）／`design.md`（+28）。**零 SQL migration**，STG／POC 未動

**關鍵決策**
- 🔴 **CM-1072 由決策者裁定納入 FR-060**：原本被劃在本 arc 之外（決策者說「那個不管他」），但實作後發現它改的就是 FR-060.3 的抽取服務、程式碼已在裡面、DEV 已生效。決策者原話：「那看起來 1072 必須納入 fr-60 對吧，算是延伸題目…既然要把功能做完整」
- **url 型代下載的三條不變式**（改這塊之前必須先讀懂）：①**掃描路徑完全不動**，agent 仍原樣把 URL 交給 `cinc-auditor exec`，抓的永遠是即時內容不是平台快照 ②**下載內容不落儲存**（`source_type` 維持 `url`、`file_id`／`sha256` 維持 `NULL`）——存成 file 型快照會破壞雙軌語意，且掃描與抽取從此可能對不上、對不上時沒人知道該信哪個 ③**下載必須在 `session_scope()` 之外**，網路 IO 最多等 60 秒
- **「url 型明細會靜默偏離」的方向定甲案**：開明細頁時對來源 URL 發輕量請求比對 ETag／Last-Modified，一樣直接顯示、不一樣才背景重抽。⚠️ **可行性未驗證**（GitHub 動態產生的 tarball 不一定給穩定 ETag）。被排除：乙案（開頁無條件重抽，被開頁頻率放大）、丙案（自動長 v2——url 型會出現同一 URL 有 v1/v2/v3，而掃描永遠拉最新 git 內容，**任務綁的版本 uid 指不到掃描實際用的東西**，讓「綁版本」既有契約自我矛盾）。已另開 Notion 卡追蹤

**教訓**
- 🔴 **派工前要查當前 HEAD 有沒有相關異動，不能只憑幾小時前的盤點**——協調者把「url 型無法抽取」當既定事實寫進三份派工單，而該事實在派工當下**已被 commit `25045758` 推翻**。SPEC agent 以程式碼為準沒照抄簡報，是對的判斷——這也印證了**派工單該寫「去讀什麼」而不是「事實是什麼」**
- **「技術做不到」與「產品範圍不含」要分開講**：url 型不抽取原本掛在 FR-059 P5「平台完全不經手檔案」名下，聽起來像技術限制，實測 CINC 原生就吃 URL（`cinc-auditor json <tarball 網址>` 解得出 59 條）。P5 真正涵蓋的是「掃描路徑不代管私有 repo 憑證」，而抽取是 FR-060 才有的另一個面向

**推翻了什麼**
- ① 推翻第 4 棒 SUMMARY／STATE／LOG 寫的「**url 型無法抽取、`failed` 是設計內終態不是故障**」——CM-1072 之後已支援，錯誤訊息「平台不代為下載…請改以上傳壓縮檔的方式建立版本」不再出現
- ② 更正第 4 棒的 DEV 數字：**控制項 1,641 → 2,131**、**`succeeded:3 failed:1 pending:9` → `succeeded:5 failed:0 pending:8`**（原本 `failed` 那支 dev-sec 基準已抽取成功）。主檔 13／版本 13／分類字典 13 不變，三環境未動的結論不變

---

## 第 6 棒 — 2026-08-04（主線收尾 ＋ 四張延伸卡）

**做了什麼**
- 主線收尾：SPEC（435→839）／使用手冊（163→294）／SUMMARY 新建 316 行／STATE／LOG ＋ SPEC 的 html build 產物，六份一次 commit
- 新開四張延伸卡：CM-1075（url 型 ETag 比對，已派出實作中）／CM-1076（8 支基準批次抽取，已派出）／CM-1077（版本與基準的修正與刪除）／CM-1078（清單操作按鈕收進 menu）
- 定 CM-1078 先於 CM-1077 的順序：兩張動到同一個檔（`DetectionProfileManageView.vue` 操作欄），先收乾淨結構再加新動作

**commits**
- BE `d064cb61` `docs(FR-060): 全案收尾 — SPEC／使用手冊／SUMMARY／STATE／LOG（CM-1054~1066＋CM-1072）`，6 檔 +3,435／-759。**未 push**
- 實查未 push 數：BE **16 支**、FE **7 支**（FE 第 7 支是 `9b741c8`，CM-1072 的 FE 側）

**關鍵決策**
- 🔴 **CM-1077 的判準是客觀的「有沒有被使用過」，不是問使用者意圖**。從未被使用過 → 可就地修正來源（版號不動、重抽控制項）／可刪除；已被使用過 → **一律凍結**，只能建新版本。刪除及於主檔，但主檔判準更嚴——「從未產生過任何掃描結果」，因為任務可能已刪而報告與證據還在。
  **被排除的方案**：協調者原設想「已被使用時跳確認框問『確定要更新嗎？會影響既有資料』讓使用者選」。決策者原話否決：「萬一有被掃過，下次掃同版本結果不一樣，也很奇怪」——`uid` 是凍結契約、`sha256` 是對帳基準，同一版本 uid 在不同時間指向不同內容，之後回頭看掃描報告沒人能確定當時掃了什麼。**在 GRC 系統裡這是稽核可信度問題，不是 UX 取捨**，所以不能交給使用者當次決定。
  觸發此題的 DEV 實例：決策者測 SSRF 時產生的「SSRF」基準，v1 `http://192.168.50.1/x.tar.gz`（被 SSRF 防護擋下）、v2 `https://...`（為修正而版更），兩版皆 `failed` 且被任務引用 0 次——版本歷史留下「從來不能用」的孤兒版本，看歷史的人分不出是舊標準還是當初手殘。

**教訓**
- 🔴 **收尾 commit 前必須先看工作區有什麼不是自己做的**。本棒本要統一 commit，`git status` 才發現 6 個程式碼檔（`source_etag`／`source_last_modified` 兩個新欄位 ＋ `safe_http_fetch.py` +126 ＋ 抽取服務 +206）是**另一個 session 的 CM-1075 實作中異動**，另有一支未追蹤 migration `scripts/sql/2026-08-04-fr060-3-dpv-source-validators.sql` 同屬該線。若用 `git add -A` 或 `-am` 就會把別人做到一半的東西一起帶走。**多 session 併發是本專案常態，收尾的 commit 一律顯式列檔名。**

**推翻了什麼**
- 更正第 5 棒 STATE 記的未 push 數與 CINC 安裝狀態：BE **15→16 支**、FE **6→7 支**；CINC Auditor 從「僅開發機已裝、三台部署機未確認」更正為**四台皆已安裝**（各機 `CINC_AUDITOR_CMD` 路徑解析實測仍未做）。

**留給下一棒**：主線只剩 push 與上版（皆需決策者放行）；四張延伸卡中 CM-1075／1076 已派出、CM-1078 應先於 CM-1077。

---

## 第 7 棒 — 2026-08-04（延伸卡收斂 ＋ CM-1077 拆卡）

**做了什麼**
- 接手盤點、驗收 CM-1075／1076、標 CM-1076 為 `Done`
- 與決策者討論 CM-1077 的「被使用過」判準，定出**軟刪穿透**規則
- 新開 CM-1079（專案軟刪除無法檢視／復原）作為 follow-up 記錄
- 派三隻 subagent 平行寫 CM-1077 三張子卡的 md（**未上 Notion**，留給下一棒）

**commits**
- BE `c3b10b32` `docs(FR-060): CM-1077 拆成三張子卡的派工內容（待上 Notion）`，3 檔 +580。**未 push**
- 決策者本人已於本日 push 先前累積的 BE 14 支／FE 8 支

**關鍵決策**

🔴 **CM-1077 的「被使用過」判定要穿透軟刪除的專案**——引用只計入「活著的專案」（`JOIN project_extensions WHERE deleted_at IS NULL`）。

決策者提出的問題：「軟刪除專案 user 看不到，也沒辦法刪除，然後我們要刪除設定檔的時候卻被擋下，這樣 User 會困惑」。這是真的死結——實查確認 `grc_project_repo_impl.py` **11 處查詢全部帶 `deleted_at IS NULL`**，沒有任何角色（含 admin）看得到已刪除專案，也沒有復原端點。DEV 209 個專案有 204 個已軟刪（97.6%），使用者實際只看得到 5 個。照字面判定，使用者會被一個**他看不到、無從查證、也無法處理的專案**擋住，且沒有任何自救途徑。

定案原則：**擋下的理由必須是使用者看得見的**。GRC 語意上也站得住——專案已刪除代表那份稽核工作已被放棄。

**被排除的三個方向**（決策者主動提出，一併評估後排除）：
- **加專案硬刪除**——GRC 系統裡專案硬刪等於銷毀稽核軌跡（AP/AR/POA&M/證據/報告全連著），要動的 FK 與 cascade 範圍極大，風險遠超過它要解的問題
- **archive table 模式**——搬 204 筆專案及其關聯樹是獨立 arc 的工程量，且搬完「引用指向的專案查不到」的問題**依然存在**，只是換個形式，沒解到根本
- **保守擋下（JOIN 不到專案就擋）**——安全但與決策者的原意相牴觸，專案刪掉後那支基準永遠鎖死

**主檔層不做軟刪穿透**（與版本層的差異）：刪主檔會連帶刪掉所有版本與控制項，而任務可能已被刪但報告與證據還在，那時 profile 仍是稽核軌跡的一部分。母卡原話「從未產生過任何掃描結果」，門檻照這句走，寧嚴勿寬。

**CM-1077 拆三張的拆點選在「判定」與「動作」之間**：判定規則是難點與風險所在（三來源、軟刪穿透、兩種嚴格度），動作本身是常規 CRUD。**判定寫錯是資料安全問題，動作寫錯只是 UI 問題**，不該綁在同一次驗收裡。

**教訓**
- 🔴 **`_` 在 SQL LIKE 是單字元萬用字元**——協調者查 `agent_tasks` 帶 `_profile` 的筆數時用了 `params::text LIKE '%_profile%'`，回 **32 筆**；改用 jsonb 存在運算子 `params ? '_profile'` 才是正確的 **7 筆**。差了四倍多，而且錯誤方向是**高估**，若拿它當判定基準會誤擋一堆本來可刪的版本。已寫進 `.1` 卡的必讀陷阱。
- 🔴 **同一個概念在系統裡有兩套不同步的真相時，要查清楚哪一套是活的**——`projects.status='archived'` 看起來就是「已刪除」，但實查發現：①`status` 與 `deleted_at` 不同步（8 筆已軟刪但 status 仍 `in_progress`）②`archived` 這個 status **現行流程根本沒有寫入端**（grep 過 `app/` `domain/` `api/`，只有讀取端在比對），那 196 筆是歷史遺留。**用直覺上最像的欄位會判錯**，唯一可靠的是 `project_extensions.deleted_at`。
- 🔴 **本體一次輸出太長會撞串流中斷**——協調者原本要一次建三張 Notion 卡，連續撞 `API Error`（與第 2 棒的 `Response stalled mid-stream` 同類）。決策者裁示改成「先寫成 md、下個 session 再上 Notion」＋「派 subagent 去跑」。三隻 subagent 平行寫、各約 200 行，全部一次成功。**大量結構化輸出要外包，不要本體硬幹。**
- **subagent 帶著充分的實查事實派出去，會自己再撈到更多**——三隻各自查到一件派工單沒寫、但會直接影響實作正確性的事實：既有 `count_referencing_tasks` 的 ref-count 實作鏈可照抄（呼應「禁止重複造輪子」）、`current_version_id` 的 FK 是 `ON DELETE SET NULL` 故不可拿它當業務規則（會靜默清空指標而非報錯）、該頁已有兩種 disabled 原因機制故本卡的是第三種（四種並存要取聯集）。

**推翻了什麼**
- ① **推翻第 6 棒定的「CM-1078 必須先於 CM-1077」**——實查 `DetectionProfileManageView.vue` 確認 **CM-1078 已落地**（`buildActionMenuItems(row)` 的 menu 結構已在），CM-1077.3 可直接加 menu item，兩張卡的順序約束解除。
- ② **更正第 6 棒 STATE 的「CM-1075 實作中異動卡在工作區、不可 `git add -A`」警語**——CM-1075 已完成並 commit（BE `6964c89f`／FE `209bf88`），工作區已清乾淨。顯式 `git add` 的紀律不變（多 session 併發仍是常態）。
- ③ **更正 DEV 數字**：主檔 13→**14**、版本 13→**15**、控制項 2,131→**4,907**、抽取 `succ 5/fail 0/pend 8` → **`succ 13/fail 2/pend 0`**。CM-1076 已把原 13 支全數抽完（pending 歸零）；2 支 `failed` 是決策者測 SSRF 防護時建的「SSRF」基準 v1/v2，**不是故障而是防護正常運作的證據**，且正是 CM-1077 的驗收目標。
- ④ **修正母卡 CM-1077 寫的「已抽取狀態沒有重抽入口，本卡要順便補」**——CM-1075 已部分處理（**只在「來源已過期」時**給按鈕），一般 succeeded 態仍無入口。已寫進 `.2` 卡並列為 STATE follow-up 第 10 項。

**留給下一棒**：三張子卡 md 已寫好待上 Notion（🔴 **一次 `create-pages` 建完保證連號**，建完回填母卡 CM-1077）；上版 STG／POC 仍需決策者放行（**四支** migration 只套 DEV）。

---

## 第 8 棒 — 2026-08-04（CM-1078／CM-1080 兩張 UI 卡落地並收尾）

**做了什麼**
- CM-1078：掃描設定檔管理頁操作欄 7 顆圖示 → **單一 kebab 選單**
- CM-1080（本棒新開，決策者當場追加）：兩頁加「全部展開／收合」＋ 展開列視覺降階
- 收尾：spec ＋ 使用手冊 ＋ `frontend-overview.md` §3.4 ＋ 兩張 Notion 卡收 `Done` ＋ memory 一條

**commits**
- FE（✅ 決策者已 push）`4c6ebd0`（操作欄收 menu）`e569492`（檢視類也收進去）`4c41169`（全部展開＋子表降階）`d18ab4c`（註解卡號修正）`8bf5f64`（控制項頁比照＋樣式抽全域）
- BE（❌ 未 push）`aa2076a0`（spec ＋ 使用手冊）`cbc083ea`（frontend-overview §3.4 登記新 class）`399081b4`（STATE/LOG ＋ 重 build 需求站）

**關鍵決策**

🔴 **收合操作時，「沒有這個動作」與「不能做這個動作」必須用不同手法呈現**。原本散列按鈕的做法是「`can_edit === false` → 整組 `v-if` 不渲染 ＋ 旁邊一顆鎖頭解釋」，收進 menu 後若照抄，使用者只會看到一個少了幾項的選單、無從得知為什麼。定案：**語意上沒有的不放**（自有列的「複製為自有」、無現行版的「版更」與「檢視控制項」）、**存在但不能做的放但 disabled**。原因**講一次**放選單頂端（Menu `#start` slot），個別缺 capability 才在該項 label 後綴。

🔴 **唯讀說明指向的「出路」不可跟著 disabled**——說明寫「您可以複製為自有後編輯」，那顆「複製為自有」在公版唯讀時就必須仍可按（它寫的是新的租戶列、不動公版）。跟著灰掉等於把出口堵死。

**鎖頭圖示改掛「來源」欄的公用版 Tag 旁**：唯讀是「這一列的性質」不是「某顆按鈕的狀態」，掛在來源標籤旁讀得出因果（公版 → 所以唯讀），且操作全進選單後也不會無處可掛。

**展開列樣式抽成全域 class**（`row-expansion-panel` / `-title` / `-count` / `-subtable`）放 `_theme-overrides.scss`，兩頁共用。依 repo 規範「2+ 元件共用 → 全域」；`menu-item-danger` / `dpm-menu-note` 則是**被迫全域**——PrimeVue Menu popup 預設 `appendTo="body"`，元件的 scoped style 到不了。

**全部展開刻意不 invalidate 版本快取**：展開 N 列＝N 個子元件掛載，逐一失效就是打 N 個請求；而快取最舊只到「上次載入列表」那一刻（`fetchProfiles` 會全清），與主列表欄位的新鮮度**同級**——多打 N 次換不到實際更新的資訊。控制項頁的全部展開則**只作用於當前篩選結果**（展開列是純本地渲染沒有請求成本，但 DOM 會膨脹；且使用者按下那一刻想的是「把我現在看到的攤開」）。

**教訓**
- 🔴 **Notion `Case No` 是 `auto_increment_id` 唯讀欄位，不可在 `create-pages` 帶入**（帶了會 400 `type is read-only`），而且**實際配到的號碼無法事先推測**——本棒依「目前最大是 1078」推測新卡是 1079、寫進程式碼註解，實際卻配到 **1080**（1079 已被第 7 棒的專案軟刪除卡佔走）。**建卡完必須 fetch 回來看實際 Case No，再回填程式碼／文件裡的引用**（本棒為此多花一支 commit `d18ab4c`）。
- **「留最高頻的一兩顆在外面」這個常見建議，在圖示語意相近時不成立**——第一版留了「檢視」與「檢視控制項」兩顆在操作欄外，決策者當場回饋「兩顆並排讀起來還是像工具列，眼睛跟清單長太像，user 一定會誤會」。全部進選單、每項都有文字，反而更清楚。
- **Dialog 開關動畫期間的 overlay 會吃掉後續點擊**——瀏覽器自動化連續操作時，關 dialog 後要等 2～3 秒再點下一個目標，否則點擊落在 overlay 上（本棒撞到兩次，症狀是「看起來沒反應」）。

**推翻了什麼**
- **更正第 7 棒 STATE 的「CM-1078 已落地」**——第 7 棒實查看到 `buildActionMenuItems(row)` 就判定已落地，但那是**本棒稍早的中間態**（留兩顆在外面）。本棒完成後才是最終形態：**操作欄只剩單一 kebab**，讀取類也收進去了。STATE 對應列已改為 `Done` 並註明。

**留給下一棒**：CM-1077 三張子卡仍待上 Notion（第 7 棒產出的 md）；**CM-1077.3 加 menu item 時務必照本棒定下的 disabled 規則**（見 spec §4 gate 表與 STATE 該段）；上版 STG／POC 仍需決策者放行。**BE 三支文件 commit 未 push**（FE 五支決策者已自行 push）。

> 本 block 收尾時就地更正過一處：原寫「commits 全部未 push」，實查 `git rev-list origin/..HEAD` 為 0，FE 五支決策者已 push，僅 BE 未推。STATE 對應表格同步改為逐列標示 push 狀態。

---

## 第 9 棒 — 2026-08-04（Notion 建卡收口 ＋ CM-1082 落地）— 協調者

**做了什麼**
- **CM-1077 三張子卡上 Notion**：CM-1082（`.1` 判定服務）／CM-1083（`.2` 修正來源＋刪除）／CM-1084（`.3` 前端接 menu），Case No 連號
- **母卡 CM-1077 回填**「已拆成三張子卡」段（連結／依賴順序 `.1`→`.2`→`.3`／拆卡理由），並修正原寫的「已抽取狀態沒有重抽入口，本卡順便補」為現況（CM-1075 只補了「來源已過期」態，一般 succeeded 態仍無 UI 入口；後端流轉歸 `.2`、前端入口歸 `.3`）。母卡狀態維持 `Not started`
- **CM-1072 收 `Done`**（決策者手測通過，補三條不變式與 SSRF 說明）；**母卡 CM-1054 收 `Done`**（內容全量重寫五段，含明列的「尚未做」七項）
- **CM-1082 派工並驗收落地**；`.2` 卡（CM-1083）md 對齊 `.1` 實況並同步回 Notion
- **POC／STG 唯讀盤點**（純 `SELECT`，未動任何狀態）

**commits**
- BE `17e977eb` `feat(FR-060.2): 檢測基準「是否被使用過」判定服務（CM-1082 / CM-1077.1）`，8 檔 **+540**。**未 push**
  - 新增 `infra/detection_tools/repository/detection_profile_usage_query.py` 124 行（三來源 UNION ALL，`find_refs()`）
  - `app/.../detection_profile_service.py` +98（`get_version_usage()` / `get_profile_usage()` / `_build_usage()`）
  - `domain/.../detection_profile_domain_service.py` +11（`list_all_versions()`，不分頁、判定專用）
  - route +53／serializer +26／`api/detection_tools/__init__.py` +15（兩支唯讀端點）／DI wiring +9
  - `test/test_detection_profile_usage.py` 204 行 11 條
- 工作區未 commit：`cards/CM-1077-2-edit-and-delete.md`（185→235，+51/−1）
- 本棒起算 BE 未 push **5 支**：`aa2076a0` `cbc083ea` `399081b4` `7b987e8c` `17e977eb`（前四支是第 8 棒的）

**Notion**：CM-1082／1083／1084 新開；CM-1082 → `修正待驗證`；CM-1072 → `Done`；CM-1054 → `Done`；CM-1077 回填後維持 `Not started`

**關鍵決策**
- **Notion 建卡改「兩階段」**：先一次 `create-pages` 建三張**薄卡**（標題＋properties＋摘要）鎖住連號，再逐張 `update-page` 填完整內容。四次呼叫全成功、未撞串流中斷。**被排除的**：第 7 棒本體一次送三份長內容的做法——已實測會撞 `API Error`（與第 2 棒 `Response stalled mid-stream` 同類）。薄卡先建保證了連號這個唯一無法事後補救的性質，內容則可分次補
- **協調者實跑驗證而非採信 subagent 自報**：`pytest test/test_detection_profile_usage.py` → **11 passed**；四條硬性禁令逐條 grep 實查通過（無 `LIKE '%_profile%'`、無 `status='archived'` 當軟刪判準、canonical `build_profile_ref()`／`extract_profile_uid()` 有實際呼叫非自寫 `startswith`、route 註冊順序正確）

**教訓**
- 🔴 **STATE 抄 Notion 狀態必然過期，派工前要現查**——本棒用 SQL 一次撈 20 張 FR-060 卡，與 STATE 記載對照發現**大面積漂移**：CM-1055/1056/1057 已全 `Done`（STATE 只寫「子需求卡」）、CM-1060~1065 已全 `Done`（STATE 寫「修正待驗證」）、CM-1066 已 `Done` 且早已完整回寫（STATE 寫「尚未回寫」）、CM-1072 已可收（STATE 寫「狀態待標記」）。協調者照 STATE 寫的派工單交代 subagent「兄弟卡停在修正待驗證，一律不要動」——**那份資訊本身就是過期的**（subagent 守住紀律沒動兄弟卡狀態，是對的）。**Notion 是多方會改的外部真相，交接文件只能當索引不能當狀態來源**；STATE 該表已加警語
- 🔴 **fail-open fallback 是守門測試的假性通過來源**——`_build_usage()` 有一條 `if self._usage_query is None: return {"in_use": False, ...}`（本意是給不組全套依賴的單元測試用）。這條讓「守門有效」與「守門根本沒被呼叫」**在測試裡長得一模一樣**：`.2` 的 409 測試若 mock 掉 `usage_query` 或漏組依賴，判定一律回「未使用」，測試會綠但守門沒測到。已寫進 CM-1083 完成定義第 13 條（要求斷言 `in_use=true` 那條路徑確實走到）。
  ⚠️ 附帶：協調者第一次檢查時 DI 尚未 wiring，那時這條 fallback 在**真實環境**就會生效（判定全面回「沒被使用過」，`.2` 接上去等於全放行）。後續 commit 已補 DI wiring，退化成僅測試路徑可達
- 🔴 **exclude 式過濾會靜默吃掉你沒想到的東西**——查 CM-1082 進度時用 `git status --short | grep -vE '\.png|\.docx|...'` 濾雜訊，把 `app/` 那個已修改的檔一起濾掉了，因而**誤判「app service 未實作」**。應該用 `git status --porcelain` 看全量，或至少改 include 式（`grep -E '\.py$|\.sql$'`）

**推翻了什麼**
- ① **推翻第 7 棒 STATE 記的「CM-1066 尚未回寫」**——CM-1066 **早已是 `Done` 且早已完整回寫**（含四支 commit `bbcb882`／`07b8a7d`／`e4e7967`／`7274d13` 與 PrimeVue 展開列根因）
- ② **推翻「CM-1077 子卡會接在 1080 後面」的預期**——**CM-1081 不屬於 FR-060**（被別條線佔走），子卡從 **1082** 起跳。這是第 8 棒教訓「Case No 無法事先推測、建完必須 fetch 回來看」的第二次實例
- ③ **推翻 STATE Notion 卡片樹整片記載**（見上方教訓①），已按實查重寫並加「派工前現查」警語
- ④ **更正 §5 第 2 項「POC 環境唯讀確認仍未做」**——本棒已完成：POC `config.detection_tool_profiles` 存在、**12 筆**；STG **10 筆**；兩環境 `detection_profile%` 新表數皆 **0**。四支 migration 只套 DEV 的結論不變

**留給下一棒**：CM-1083（`.2`）前置已就緒、卡已對齊實況，**可直接派工**；CM-1084（`.3`）待 `.2` 完成。**CM-1082 與 CM-1075 待決策者手測**（CM-1082 卡內三條 DEV 實測斷言需起 BE 打端點，11 條單元測試替代不了）。上版 STG／POC 仍需決策者放行；SPEC／手冊補 CM-1075 行為仍未做。

---

## 第 10 棒 — 2026-08-04（CM-1077 三張子卡全數落地 ＋ schema 命名議題）— 協調者

**做了什麼**
- **CM-1077 三張子卡全數落地**：CM-1083（`.2` 修正來源 ＋ 硬刪，BE 寫入端）／CM-1084（`.3` 兩動作接進操作 menu，FE）；另修 CM-1093（`.2` 迴歸測試整批跑 6 條 fail）。連同第 9 棒的 CM-1082，**四張卡皆 `修正待驗證`**，待決策者手測
- **分頁預設 10 → 20**（決策者口頭交辦、無 Notion 卡）
- **新開兩張 schema 命名整理卡**：CM-1094（母案）／CM-1095（`config` → `detection`），現階段只記錄不做

**commits**（BE／FE **皆未 push**）
- BE `dddfe7cf` CM-1083（`.2`）修正來源 ＋ 硬刪，9 檔 **+790**
  - 三支端點 `PATCH /detection-tool-profile-versions/<uid>/source`／`DELETE /detection-tool-profile-versions/<uid>`／`DELETE /detection-tool-profiles/<uid>`
  - 三個 error code `DETECTION_TOOLS_409009`（版本已被使用）／`409010`（主檔底下有版本被使用）／`409011`（current version 不可單獨刪）
  - `test/test_detection_profile_edit_delete.py` 19 條；**無新 migration**（CASCADE 在 FR-060.1 拆表時已設好）
- BE `fe615d3e` CM-1093 補 autouse patch logger，1 檔 **+17**
- FE `d6e71e1` CM-1083 的 error code i18n 三語系，3 檔 +9
- FE `88f2e13` CM-1084（`.3`），8 檔 **+818/-31**：新增 `components/ProfileSourceDialog.vue` 207 行、`composables/useProfileUsage.js` 122 行；`DetectionProfileManageView.vue` +170/-10、`ProfileVersionTable.vue` +185/-21、i18n 中英各 +21、`api.js` +15、`DetectionToolProfileService.js` +77
- FE `247b6f5` 分頁預設 10 → 20，1 檔 +1/-1

**Notion**：CM-1083／CM-1084／CM-1093 → `修正待驗證`（連同 CM-1082 共四張待手測）；CM-1094／CM-1095 新開，皆 `Not started`

**關鍵決策**

🔴 **`config` schema 更名為 `detection`，表名不動，併進 FR-060 上版執行**。

觸發點是決策者質疑「為什麼整個功能的資料都被放進 config schema」。實查確認本專案 schema 混用兩種不相容的切法——`oscal`(58)／`compliance`(45)／`survey`(15) 按**業務領域**切，只有 `config`(9) 按**資料種類**切；而決策者原意的「系統設定、選單設定」其實早在 `public`（`system_configs`／`system_menus`／`ui_routes`／`roles`／`tenants` 等），`config` 實際裝的是檢測工具這單一功能的全套資料，含 `detection_profile_controls` 這種數千筆的業務明細表——**那不是設定**。業界慣例是切「限界上下文」而非資料種類，理由有三：按種類切會無限膨脹成雜物間且單一功能被拆散；schema 是權限與遷移的單位，按領域切未來拆服務可直接搬走；「設定」不是穩定分類（`detection_profiles` 有版本、有明細、有狀態機，行為完全是業務實體）。

**被排除的命名**：`detection_tool`——schema 內不只有 tool，還有 profile、taxonomy、job 綁定；`detection` 才是這個領域的字，程式碼裡也一直是。
**被排除的選項**：連表名一起改（`detection.profiles`）——名字重複一點可接受，換來省下改 8 個 model／mapper／所有 raw SQL 的成本，也保住 grep 可搜性。

🔴 **時機裁示：併進 FR-060 四支 migration 的上版，不單獨排**。理由是這是唯一便宜的時機——分開做等於為了一行 SQL 再排一次上版、再驗一次三環境；而 `config` 每多長一張表、每多一條 FK 指過來成本就跳一階，**現在零跨 schema FK 是最好的狀態**。母案 CM-1094（含 `public` 那 56 張的分流）則照決策者裁示「先不用，之後會再做一次大整理」。

🔴 **重要前提：這不是 DEV-only 操作**。`config` schema 本身**在 STG／POC 都已服役**（FR-056 v1.11.0 帶進去的），兩環境各 5 張表（`detection_tools`／`tenant_detection_tool_configs`／`detection_tool_param_schemas`／`detection_tool_profiles`／`job_execution_detection_tools`），所以改名會動到 POC（等同 production）。成本盤點（實查）：跨 schema FK **零**、DB 端一行 `ALTER SCHEMA` 即可（RLS/GRANT 跟著物件走）、程式碼 8 個 model 檔、舊 migration 檔不改。**必須等決策者當次明示放行。**

**教訓**
- 🔴 **exclude 式過濾會靜默吃掉你沒想到的東西**——查 CM-1082 進度時用 `git status --short | grep -vE '\.png|\.docx|...'` 濾雜訊，**把 `app/` 那個已修改的檔一起濾掉**，因而誤判「app service 未實作」、對決策者回報了錯誤的半成品結論。應該用 `git status --porcelain` 看全量，或用 include 式（`grep -E '\.py$|\.sql$'`）。（第 9 棒已記過一次同類，本棒是複發，故再記一次並升級為「盤點類命令一律看全量」。）
- 🔴 **grep 命名法要涵蓋 kebab-case，否則會誤判「這個 prop 不存在」**——查 FE 分頁設定時 grep `rowsPerPageOptions`（駝峰），漏掉實際寫法 `:rows-per-page-options`（kebab-case），因而在派工單裡寫下「該頁沒有 rowsPerPageOptions、使用者不能自選筆數、不要順手加」——**前提整個是錯的**，該 prop 一直都在（L711）。subagent 照指示沒動它，結果正確但理由是錯的。**Vue template 的 prop 有兩種寫法，grep 要兩種都試。**
  ⚠️ 附帶：這次僥倖沒事是因為 20 剛好在 `[10, 20, 50]` 清單內。**若改成不在清單裡的值（如 15），PrimeVue 的 paginator 選擇器會顯示空白**——改預設分頁時必須同時確認新值在 `rows-per-page-options` 內。
- 🔴 **多 session 併發時，`git add <檔名>` 也不夠安全**——分頁那個改動下手時，`DetectionProfileManageView.vue` 裡**已有另一 session 約 97 行 `.3` 的未 commit 內容**。單純 `git add <檔名>` 會把人家做到一半的功能整包 commit 走。正確做法是**只抽自己那個 hunk 用 `git apply --cached` 進 index**，commit 後確認對方 6 個檔仍完好留在工作區。→ **紀律升級：同一檔案有他人未 commit 內容時，顯式 `git add <檔名>` 仍不足，要 hunk 級別暫存。**（這是第 6 棒「收尾 commit 前必須先看工作區有什麼不是自己做的」的下一層——看到了還不夠，同檔混雜時要更細的粒度。）
- 🔴 **Notion 的 Cloudflare WAF 會擋含 shell 指令字串的 POST**——CM-1093 建卡時，卡片內容含 `pytest ... -p no:cacheprovider --continue-on-collection-errors` 完整指令行，連續被 WAF 拒。**改成散文描述重現方式即可通過。** 之後寫 Notion 卡若要放指令，拆開或改描述。
- **`.2` 加了稽核 log 埋點就會撞本專案已知坑**——`.1` 判定服務唯讀沒有埋點所以測試無事，`.2` 的刪除／改來源加了 8 處稽核 log，整批跑時前面的測試已初始化 logging、`DBLogHandler` 會試圖寫 DB 撞 `SessionLocal is None`。**六條 fail 全是走到埋點的成功路徑**（被擋回 409 的反而沒事，還沒走到 log 就 raise 了）。解法是 autouse fixture ＋ monkeypatch 換成真的 `logging.getLogger("test")`（比照 `test_audit_round_app_service.py:36-39`），**不是逐條包 context manager**（19 條裡 6 條會踩，逐條容易漏且未來新增又會踩）。

**推翻了什麼**
- ① **推翻第 9 棒 STATE 寫的「CM-1081 不屬於 FR-060（被別條線佔走）」的模糊記載**——已查明它是**「升級迴歸」那條 arc 的母案**，子卡 CM-1085~1092＝T-0~T-6。⚠️ **Notion 上現有兩條 arc 交錯編號，看卡號時不可依編號連續性推斷歸屬**：1082/1083/1084 是 FR-060，1085~1092 是升級迴歸，1093 又回到 FR-060。
- ② **BE `b393e1d6`（CM-1086 migration manifest 對齊機制，4 檔 +541）不屬 FR-060**，是升級迴歸那條線的 commit，只是同在未 push 清單裡。STATE Git 節已改為逐列標示「屬本 arc？」。
- ③ **更正 STATE 的未 push 數**：BE 5 → **8 支**（其中 7 支屬 FR-060）、FE 0 → **3 支**（全屬 FR-060）。實查命令 `git log --oneline origin/feature/e2e-env-build..HEAD` 於兩 repo 各跑一次。
- ④ **更正 DEV 數字，並標明它正在變動**：第 7 棒記的「主檔 14／版本 15／控制項 4,907／failed 2」已不成立——本棒同一分鐘內連查三次得到 **14 → 12 → 11**（決策者正在手測 CM-1084 的刪除）。原 2 支 `failed`（「SSRF」基準 v1/v2）已被 `.2` 的刪除驗收刪乾淨。**STATE 已改為「不要當基準、一律現查」並附命令。**
- ⑤ **推翻 STATE follow-up 第 11 項的預期「CM-1077.2 會碰到一般 succeeded 態的重抽入口」**——`.2` 只讓「改來源後」自動回落 `pending` 重抽，**沒有補主動重抽入口**，該條仍未解。

**留給下一棒**
- **四張卡（CM-1082／1083／1084／1093）待決策者手測**，手測重點與 DEV 取樣建議在 STATE §4 第 1 項的表格
- **上版 STG／POC 需決策者放行**；🔴 上版時**一併執行 CM-1095**（`config` → `detection`），DB 與程式碼必須同批、改完重啟 BE
- **SPEC／手冊未補的行為累積三批**：CM-1075（ETag 比對）、CM-1083（三支寫入端點 ＋ 三個 409 守門）、CM-1084（menu 兩動作 ＋「刪除與停用只出現其中一項」規則）
- CM-1077 母卡待三張子卡手測通過後才收 `Done`

---

## 第 11 棒 — 2026-08-07（全案結案）— 協調者

**做了什麼**
- 決策者明確下令收尾，本棒為純文件與 Notion 更新工作（不改程式碼、不碰 DB 寫入、不 commit 程式碼、不 push）
- **母卡 CM-1054 追加「全案結案」段**（`insert_content` position end，不覆蓋既有五段）：三環境 registry 對齊清單、BE／FE 均已 push、POC follow-up 標記、決策者裁示原文
- **新開 follow-up 卡 CM-1104**：`FR-060 POC 12 支公版尚未觸發控制項抽取——待管理員在 UI 逐支點擊`，properties 專案 `CM`／來源 `雷門`／作業人員 `雷門`（此事是管理員自己在 UI 操作，非 Claude 實作）／狀態 `Not started`／需求編號 `FR-060`
- **STATE 改寫 §2／§4**：一句話改為「全案結案」；補三環境 registry 對齊實查結果；Git 段改為「均已 push、0 未推送」；§4 下一步分組改為「已完成／結案後 follow-up／未確認狀態」

**commits**：BE `<待收尾時填入>`（STATE＋LOG 兩檔）。**不 push。**

**Notion**：CM-1054 追加內容成功；CM-1104 新開，`Not started`

**關鍵決策**
- 無新決策，本棒執行的是上一輪已拍板的收尾動作

**教訓**
- 無

**推翻了什麼**
- **推翻第 10 棒 STATE 記的「BE 未 push 8 支／FE 未 push 3 支」**——本棒交接派工單提供的實查數字為「均為 0 未 push（已全數 push）」，決策者已於第 10 棒之後完成推送
- **CM-1095（`config` → `detection`）執行狀態未經本棒查證**——派工單只給了三環境 migration registry 清單（`cm1047`／`fr060-1(b)`／`fr060-2`／`fr060-3` 五筆），未見 CM-1095 對應記錄；STATE 已標記為「未確認狀態」，不假設已隨上版執行，留待下一手用 `\dn` 或 `schema_migrations` 查證

**留給下一棒**
- **CM-1104**：等管理員在 POC UI 上逐支觸發「開始解析」，之後回頭確認 12 支 `extraction_status` 是否全變 `succeeded`
- **CM-1095 執行狀態待查證**（見上方「推翻什麼」）——若尚未執行，需另外找時機排入
- CM-1077 母卡、SPEC／手冊 CM-1075／1083／1084 三批行為是否已補寫，本棒未查證

---
