FR-060 檢測基準內容管理 — STATE(living,永遠只描述「此刻」)

這是 living 檔,就地 Edit 覆寫。 決策脈絡與每棒紀錄在 fr060-LOG.md(append-only)。 最後更新:2026-08-07(第 11 棒,全案結案) 收尾彙整見同資料夾 2026-08-03-fr060-arc-SUMMARY.md


§0 讀序(冷接必讀,依序)

  1. 本檔全部(尤其 §1 原始需求、§4 下一步)
  2. Notion CM-1054 母卡全文https://app.notion.com/p/3b1346da4cd081efbab5e7fa0f7e3640 決策 D1–D19 一句話版、三個必讀陷阱、階段拆分、開工前三件待拍板
  3. design.md(同資料夾,1030 行)— 建卡只需讀 §3 決策定案 + §7 拆分 + §8 驗收;真正開工實作時才需要 §4 現況接入點 + §5 詳細設計
  4. 三張已建的子需求卡(CM-1055/1056/1057)— 子任務拆法已寫在各卡「範圍」表格

硬 gate:讀完 §1 若答不出「為什麼一個瀏覽功能要順帶拆資料表」,回頭讀 CM-1054 母卡的「任務摘要」段。


§1 🧭 原始需求(先懂這個,其餘都是手段)

決策者原話:

「目前只有項目,user 完全不知道這個東西會驗證什麼,我怎麼知道我要選什麼?哪些基準可以參考,我可以先請負責人去判斷、提前先處理,而不是等報告出來才去處理。」

FR-059 做完了「掃描設定檔管理」,但平台把 profile 當成不透明的二進位檔,完全不理解內容——使用者在管理頁與任務下拉看到的只有一個名字。

支撐急迫性的實測數字TWGCB-01-014 共 234 條控制項,其中 199 條是人工待判項impact 0.0,執行時直接 skip),實際自動檢查只有 35 條、覆蓋率 15%。使用者選了、掃了、拿到一份 85% 是 skip 的報告才發現——等於白等一輪掃描。

三個需求:①瀏覽 profile 檢驗內容(核心)②修改基本資料含改名 ③分類體系。

為什麼一個瀏覽功能要拆資料表:現行單表用 (detection_tool_id, tenant_id, name) 當唯一索引——拿 name 當身分,這正是「改名改不動、唯一改名途徑是 fork 複製」的根因;而分類三軸是「這支 profile 是什麼」的屬性、不是「這一版是什麼」的屬性。現在是最便宜的時機:DEV 僅 13 筆、FR-059 上線才兩天、沒有租戶真的在用。


§2 當前狀態(2026-08-07 第 11 棒實查)

🎯 一句話:全案結案(2026-08-07)。功能與上版均完成;POC 12 支公版控制項抽取為結案後 follow-up(見 Notion CM-1104),不影響結案判定。

三環境 DB 上版已完成,registry 對齊(第 11 棒協調者唯讀實查)

DEV: cm1047 / fr060-1  / fr060-2 / fr060-3(param) / fr060-3(dpv)
STG: cm1047 / fr060-1b / fr060-2 / fr060-3(param) / fr060-3(dpv)
POC: cm1047 / fr060-1b / fr060-2 / fr060-3(param) / fr060-3(dpv)

差異僅在 DEV 用拆表 migration 原檔 fr060-1、STG/POC 用環境自適應版本 fr060-1b(原檔斷言寫死 DEV 筆數 13,另開一支環境自適應版本供 STG/POC 使用)——這是設計如此,不是落差

🔴 POC 12 支公版控制項抽取仍是 follow-upextraction_status 全部 pendingconfig.detection_profile_controls 為 0 筆。STG 已完成(10 支 succeeded/4,133 條控制項)。子表「開始解析」入口已就緒(CM-1096),管理員可在 POC UI 上直接逐支觸發,無需額外開發。追蹤卡:CM-1104Not started,作業人員 雷門)。原因:登入 POC 需 captcha/Cloudflare Turnstile,AI 助手不處理密碼與人機驗證。

✅ 工作區已清乾淨(第 6 棒的警語已解除)

第 6 棒記載的「CM-1075 實作中異動卡在工作區、不可 git add -A已解除——CM-1075 於 2026-08-04 完成並 commit(BE 6964c89f/FE 209bf88)。

工作區目前已追蹤的修改只有交接文件與卡片 md(第 9-10 棒的 cards/CM-1077-2-edit-and-delete.mdfr060-STATE.mdfr060-LOG.md,第 10 棒收尾時一併 commit),其餘皆為無關的 docx/png/其他 arc 的 handoff 等未追蹤檔——絕不可 git add -A

⚠️ 但多 session 併發仍是本專案常態,commit 一律顯式 git add <檔名>、禁用 -am 的紀律不變。

設計階段:✅ 已收口

  • D1–D19 全數拍板design.md 1030 行已 commit(7e3e7b97
  • 討論稿 discussion.md + build 產物 discussion.html 已 commit(7124a473 補 D19)

實作進度:✅ 主線七張 + 延伸五張全數落地

內容 commit
CM-1060 T-1.1 三表 DDL + RLS 八段 + 13 筆搬遷 + 舊表 rename BE d7cf9abc
CM-1061 T-1.2+1.3 資料層三組 + domain/app service + 讀取端 API BE 01d0909b
CM-1062 T-1.4 派工鏈兩處破口 + 迴歸測試 BE 40fcc38d
CM-1063 T-2.1+2.2 分類 enum 表 + seed + 13 筆補登 + PUT 編輯 + 刪除保護 BE a2f2512b/FE 28f061f
CM-1065 T-3.2+3.3 抽取器註冊表 + InSpec extractor + 非同步管線 BE ec4e70b7
CM-1064 T-2.3+2.4 管理頁重構(1,239→639,拆六支)+ 下拉分組 + fallback 攤平 FE 97f9ac8
CM-1066 T-3.4 控制項詳細頁 + 摘要區 + 抽取狀態輪詢 FE bbcb882
CM-1072 url 型基準支援內容抽取(BE 代下載 + SSRF 防護),延伸納入本 arc BE 25045758
CM-1075 url 型開明細頁比對 ETag,有變更才重抽(甲案,先實測後實作) BE 6964c89f/FE 209bf88
CM-1082.1 使用判定服務(BE 唯讀,三來源 UNION ALL + 軟刪穿透) BE 17e977eb 8 檔 +540
CM-1083.2 修正來源 + 硬刪(BE 寫入端)+ 三個 409 error code BE dddfe7cf 9 檔 +790/FE d6e71e1(i18n 三語系)
CM-1084.3 兩動作接進操作 menu(FE) FE 88f2e13 8 檔 +818/-31
CM-1093 .2 迴歸測試整批跑 6 條 fail — 補 patch logger BE fe615d3e 1 檔 +17

分頁預設 10 → 20(決策者口頭交辦,無 Notion 卡):FE 247b6f5DetectionProfileManageView.vue:77pageSize = ref(10)ref(20)。該頁 DataTable 本來就有 :rows-per-page-options="[10, 20, 50]"(L711),20 在清單內故 paginator 選擇器正常顯示。 ⚠️ 未經畫面驗證——下手當時 FE 工作區有 .3 做到一半的未 commit 內容,開頁只會看到半成品且可能干擾對方,故未驗。留給決策者手測時一併看。

手測後三支 FE 修正:07b8a7d 列表分類欄拆三欄/e4e7967 中繼資料標籤中文化/7274d13 修多列展開只剩最後一筆有資料。

第 3 棒記載的「BE 目前是壞的」已解除——CM-1061(01d0909b)完成資料層改寫後恢復正常。

DEV 狀態(2026-08-04 15:42 第 10 棒實查)

主檔               11
版本               11
控制項           4,841
分類字典           13(target_type 8 + benchmark_family 5)
抽取 succeeded     11   全數抽完
抽取 failed         0   ← 原「SSRF」基準 v1/v2 已被 CM-1083 刪除驗收時刪乾淨
抽取 pending        0

🔴 這組數字正在變動中,不要當基準。第 10 棒同一分鐘內連查三次得到 14 → 12 → 11(決策者正在手測 CM-1084 的刪除功能)。要用數字時一律現查

# 帳號 cmmgr,密碼查 BE .env 的 DB_SECRET
psql -h 192.168.50.188 -p 25432 -U cmmgr -d guidant_ai_dev -tAc "
SELECT '主檔='||count(*) FROM config.detection_profiles
UNION ALL SELECT '版本='||count(*) FROM config.detection_profile_versions
UNION ALL SELECT '控制項='||count(*) FROM config.detection_profile_controls
UNION ALL SELECT 'extr:'||extraction_status||'='||count(*) FROM config.detection_profile_versions GROUP BY extraction_status;"

✅ 第 7 棒記載的 2 支 failed(決策者測 SSRF 防護時建的「SSRF」基準 v1/v2)已不存在——它們正是 CM-1083 的具體驗收目標(引用 0 次、要能被完整刪乾淨),已於 .2 實作時刪除並驗證三張表零殘留。

🔴 舊版本文件寫的「url 型無法抽取、failed 是設計內終態」已被 CM-1072(25045758)推翻:抽取時由 BE 代為下載(common/util/safe_http_fetch.py,SSRF 五道防護),拿到 bytes 後完全共用 file 型解析路徑。三條不變式——①掃描路徑完全不動(agent 仍原樣把 URL 交給 cinc-auditor exec,抓的是即時內容不是快照)②下載內容不落儲存source_type 維持 urlfile_idsha256 維持 NULL)③下載必須在 session_scope() 之外(網路 IO 最多 60 秒)。完整脈絡見 SUMMARY §2.4。

人工待判 vs 自動檢查(收尾日實查,這正是本需求的 WHY):

基準 總數 人工待判 自動檢查 自動覆蓋率
TWGCB-01-014 Ubuntu 22.04 234 199 35 15%
TWGCB-01-007 Win Server 2016 699 159 540 77%
TWGCB-Windows-2025 708 150 558 79%

舊表 config.detection_tool_profiles_deprecated_20260803 未 DROP(觀察期後另案,design.md §8.3)。

🔴 STG/POC 完全未動——收尾日實查兩環境 config.detection_profile% 新表數皆 0,三支 migration 只套 DEV。

Notion 卡片樹

🔴 本表是 2026-08-04 第 10 棒的實查快照,不是即時狀態。 Notion 是多方(決策者手測、其他 session、實作 runner)都會改的外部真相——派工或驗收前一律現查,不要照抄本表。 第 9 棒實查發現本表前一版有大面積漂移(CM-1055~1057/CM-1060~1066 已全 Done,STATE 卻仍寫「子需求卡」「修正待驗證」「尚未回寫」),並據此寫進派工單交代 subagent「兄弟卡停在修正待驗證別動」——那份資訊本身就是過期的

層級 Case No 狀態(2026-08-04 第 10 棒實查)
母案 FR-060 CM-1054 Done(第 9 棒收口,內容全量重寫五段,含明列的「尚未做」七項)
FR-060.1 資料模型重構 CM-1055 ✅ Done
FR-060.2 分類體系+編輯 CM-1056 ✅ Done
FR-060.3 抽取+瀏覽 CM-1057 ✅ Done
T-1.1 migration CM-1060 ✅ Done
T-1.2+1.3 資料層/服務層 CM-1061 ✅ Done
T-1.4 派工鏈破口 CM-1062 ✅ Done
T-2.1+2.2 分類 BE CM-1063 ✅ Done
T-2.3+2.4 管理頁 FE CM-1064 ✅ Done
T-3.2+3.3 抽取 BE CM-1065 ✅ Done
T-3.4 詳細頁 FE CM-1066 Done(且早已完整回寫,含四支 commit 與 PrimeVue 展開列根因)
url 型支援內容抽取(延伸) CM-1072 Done(第 9 棒收,決策者手測通過;已補三條不變式與 SSRF 說明)
url 型 ETag 比對(甲案) CM-1075 修正待驗證(待決策者手測)
8 支基準批次抽取控制項 CM-1076 ✅ Done
版本/基準的修正與刪除(未用過才可改可刪) CM-1077 Not started(母卡;三張子卡皆已落地,待決策者手測通過後才收)
├─ CM-1077.1 使用判定服務(BE 唯讀) CM-1082 修正待驗證(BE 17e977eb,11 條單元測試綠;⚠️ 卡內三條 DEV 實測斷言待手測)
├─ CM-1077.2 修正來源 + 刪除(BE 寫入) CM-1083 修正待驗證(BE dddfe7cf 9 檔 +790/FE d6e71e1 i18n;19 條測試)
└─ CM-1077.3 兩動作接進操作 menu(FE) CM-1084 修正待驗證(FE 88f2e13 8 檔 +818/-31,小弟已在 DEV 走完 7 條手測)
.2 迴歸測試整批跑 6 條 fail(補 patch logger) CM-1093 修正待驗證(BE fe615d3e 1 檔 +17,整批 failed 80 → 回基準 74)
DB schema 命名體系整理(母案) CM-1094 Not started(🔴 記錄用,現階段不做;決策者裁示「之後會再做一次大整理」)
└─ config schema 更名為 detection(FR-060.2 CM-1095 Not started(🔴 隨 FR-060 上版一起做,不單獨排;詳見 §4 第 4 項)
清單操作按鈕 7 顆收進 menu CM-1078 修正待驗證(第 8 棒完成並收尾;操作欄最終是單一 kebab,讀取類也收進去了)
專案軟刪除後無法檢視或復原(follow-up) CM-1079 Not started(🔴 決策者裁示:優先權很後面,現階段不做,僅記錄
全部展開 + 展開列視覺降階(兩頁) CM-1080 修正待驗證(第 8 棒,決策者當場追加)

🔴 CM-1081 不屬於 FR-060,它是「升級迴歸」那條 arc 的母案(子卡 CM-1085~1092=T-0~T-6)。所以 CM-1077 三張子卡的 Case No 從 1082 起跳,不接在 1080 後面。 ⚠️ Notion 上現有兩條 arc 交錯編號,看卡號時不可依編號連續性推斷歸屬——1082/1083/1084 是 FR-060,1085~1092 是升級迴歸,1093 又回到 FR-060。

建卡採兩階段:先一次 create-pages 建薄卡鎖住連號,再逐張 update-page 填完整內容——這是第 7 棒本體一次送三份長內容撞 API Error 的對策,第 9 棒四次呼叫全成功。

🔴 CM-1077 與 CM-1078 動到同一個檔,CM-1078 要先做已解除:CM-1078 已落地並收尾,CM-1077.3 可直接加 menu item,不需重構。

🔴 CM-1077.3 加 menu item 時必須照 CM-1078 定下的規則(見 spec §4 gate 表):這一列語意上沒有的動作才不放;存在但不能做的一律放 + disabled,整列唯讀的原因由選單頂端說明列(#start slot)講一次,個別缺 capability 才在該項 label 後綴。組裝點是 DetectionProfileManageView.vue::buildActionMenuItems()

子任務卡採乙案共 7 張(CM-1060~1066),與執行 session 一對一——非第 2 棒規劃的 12 張。原 T-3.1(裝 CINC)未單獨建卡,安裝屬環境動作由決策者決定時機,程式碼與文件部分併入 CM-1065。

🔴 CM-1072 原被劃在 FR-060 之外,2026-08-04 由決策者裁定納入本 arc——它改的就是 FR-060.3 的抽取服務、程式碼已在裡面、DEV 已生效。

Git(✅ 第 11 棒實查:BE/FE 均已 push,0 未推送)

BE/FE 兩 repo 於 feature/e2e-env-build 上均已 push,工作區乾淨(git rev-list origin/..HEAD 為 0)。第 10 棒記載的「BE 未 push 8 支/FE 未 push 3 支」已由決策者全數 push 完畢。

工作區未 commit:本檔與 fr060-LOG.md(第 11 棒收尾),收尾時一併 commit。

舊表 13 筆的原始形態(供上版比對,id 為舊表 id)

id 17-24  tool=8(gcb)     t=1    SYSTEM  TWGCB-01-007~014 八支      file  v1 cur/act=true
id 25-26  tool=6(inspec)  t=1    SYSTEM  dev-sec Linux/Windows 基準  url   v1 cur/act=true
id 32     tool=8(gcb)     t=102  TENANT  twgcb-02-003-google-chrome file  v1 cur=true  act=true
id 33     tool=4(openscap) t=102 TENANT  twgcb-02-003-google-chrome file  v1 cur=false act=false  ← 孤兒主檔來源
id 34     tool=8(gcb)     t=102  TENANT  TWGCB-Windows-2025          file  v1 cur/act=true

🔴 id 32 與 33 同 tenant、同 name、同 file_id,但屬不同工具(tool 8 vs tool 4)——這是搬遷 JOIN 必須三欄的實據,也是 STG 測不出來的形態。

環境座標

環境 Host:Port DB 本案可否動
DEV 192.168.50.188:25432 guidant_ai_dev ✅ 唯一可套 migration 的環境
STG 192.168.50.188:25432 guidant_ai_stg ❌ 已服役、10 筆真資料(全 SYSTEM)
POC 192.168.50.189:25432 guidant_ai_poc ❌ 等同 production;第 9 棒已唯讀盤點(12 筆,新表 0),未做任何寫入

帳號 cmmgr,密碼查 BE .envDB_SECRET


§3 🔴 行為規範(每棒都適用)

環境紀律(最高優先)

開發期間所有 migration 只套 DEV。 STG / POC 一律等決策者當次明確指示

拆表 migration 比加欄位危險一個量級——它 rename 的是一張 STG 正在服役的表。若派工單或交接文件寫「三環境都套」,該指令本身可能就是錯的,停下問決策者

通用紀律

  • 不切 branch,就在 feature/e2e-env-build 上做
  • commit 顯式 git add <檔名>,禁用 -am
  • 不 push(等 user 明示)
  • 收尾類動作(spec / SUMMARY / memory / Notion 母卡回寫)等 user 明確下令
  • 卡住兩次就停下回報,不要第三次重試
  • 憑證禁入版控

建卡專用紀律

  • Case No 是 auto_increment,靠建立順序保證連號——同一批要一次 create-pages 建完
  • Properties:專案 CM/來源 雷門/作業人員 小弟/狀態 Not started/需求編號 FR-060.x
  • 子任務卡內容要自足到新 session 不讀其他文件能開工

§4 下一步(建議清單,不是執行授權

🎯 全案已結案(2026-08-07)。以下項目均已完成,保留原文供回顧;唯一剩餘的 follow-up 見「📋 結案後 follow-up」段。

✅ 已完成(原「立即可做」)

  1. 四張卡待決策者手測已手測通過,CM-1082/1083/1084/1093 皆已收。手測重點(原文保留):

    面向 怎麼測
    **硬刪(放行路徑) 拿一支引用 0 次的基準 → 刪除 → 確認框應寫出具體的版本數與控制項數**,刪完三張表零殘留、列表不再出現
    **改來源(放行路徑) 同一支未使用基準 → 「修正來源」換網址送出 → 版號不變**(不會多出 v2)、狀態回「待解析」、稍後自動變「解析完成」且控制項換成新來源的
    **409 守門(擋下路徑) 拿已被使用過的基準 → 「修正來源」應灰、最後一項應是停用而非刪除,選單頂端說明帶得出專案名稱**
    分頁 20 筆 進頁預設顯示 20 筆,paginator 的每頁筆數選擇器正常顯示 10/20/50

✅ 已完成(原「待排」)

  1. 上版 STG/POC已完成。四支 migration 已套三環境(registry 對齊見 §2),DEV 用原檔 fr060-1,STG/POC 用環境自適應版本 fr060-1b

📋 結案後 follow-up(唯一剩餘項目)

POC 12 支公版控制項抽取尚未觸發 —— 追蹤卡 CM-1104Not started,作業人員 雷門)。詳見 §2「三環境 DB 上版已完成」段與 CM-1104 卡內容。這不是阻塞項,是管理員自行操作的待辦(子表「開始解析」入口已就緒,逐支點擊 12 次即可,非開發工作)。

⚠️ 未確認狀態(收尾時未查證,不要假設已完成)

  1. CM-1095「config schema 更名為 detection」執行狀態未經第 11 棒確認。第 10 棒裁示「隨 FR-060 上版一起做」,但第 11 棒協調者查到的三環境 registry(見 §2)只列出 cm1047 / fr060-1(b) / fr060-2 / fr060-3 五筆,沒有看到對應 CM-1095 的 migration 記錄——這個 schema 改名是否真的隨本次上版執行,下一手需另外查證\dn 看 schema 是否已是 detection,或查 schema_migrations 有無 CM-1095 對應列)。

    背景(原文保留):config schema 本身在 STG/POC 都已服役(FR-056 v1.11.0 帶進去的),兩環境各 5 張表(detection_toolstenant_detection_tool_configsdetection_tool_param_schemasdetection_tool_profilesjob_execution_detection_tools)。成本盤點:跨 schema FK 零/DB 端一行 ALTER SCHEMA/程式碼 8 個 model 檔的 __table_args__/舊 migration 檔不改。

  2. CM-1079 專案軟刪除後無法檢視或復原——🔴 決策者裁示「優先權很後面,現在不建議做,僅記錄」。 ⚠️ 未來任何人要判「專案是否已刪除」,一律用 project_extensions.deleted_at,不可用 status='archived'

  3. CM-1094 DB schema 命名體系整理(母案)——🔴 決策者裁示「之後會再做一次大整理」,現階段只記錄,子卡 CM-1095 例外(見上方第 3 項)。

✅ 收尾類(已完成,2026-08-07 決策者下令收尾)

  1. Notion 母卡 CM-1054 已收 Done(第 9 棒內容全量重寫五段;第 11 棒追加「全案結案」段,含三環境 registry、push 狀態、POC follow-up 標記)。 CM-1077 母卡狀態:本次未查證,交接時未特別要求動它(母派工單指示「CM-1077 已是 Done,不用動它」)。
  2. SPEC 與使用手冊docs/specs/current/system-admin/detection-profile-manage.mddocs/user-manual/scan-profile-guide.md 已隨早期 commit 完成,CM-1075/CM-1083/CM-1084 三批行為是否已補寫,第 11 棒未查證,留給下一手。

其他 follow-up(未變動,供未來查閱)

  1. 三個欄位的「值」仍是英文,決策者已知悉、未決定是否翻譯:檢查類型(kernel_module 等 14 種)/適用角色(baseline/dc/dns/web)/狀態(pending-mapping)。
  2. 一支端點不在任何規格書裡POST /api/1.0/detection-tool-profile-versions/<uid>/extraction(手動重抽),FE 已在用。同路徑 GET 是抽取狀態輪詢。
  3. 舊表未 DROPdetection_tool_profiles_deprecated_20260803)——觀察期後另案,design.md §8.3
  4. 一般 succeeded 態仍無重抽入口——CM-1075 只在「來源已過期」時給按鈕。若使用者想主動重抽一支正常的基準,UI 上沒有路徑(BE 端點是有的)。
  5. 整批測試曾有 74 failed + 9 個 collection error(既有問題、非 FR-060 範圍),第 11 棒未重查現況。

上述項目除 CM-1104(已開卡追蹤)外,其餘每一項都要 user 當次單獨發令才動。


§5 開工前決策者要拍板的三件事(2026-08-04 第 6 棒狀態)

  1. BE 主機安裝 CINC Auditor四台皆已安裝:開發機(本機 macOS,7.1.7 於 /usr/local/bin/cinc-auditor)+ 三台部署機(188/189/190)。docs/claude/host-dependencies.md 第三項已補齊(授權紅線/路徑解析順序/缺了會怎樣/各主機狀況表)。 ⏳ 剩下的是各機 CINC_AUDITOR_CMD 路徑解析實測,仍列在上版前條件內。 ⚖️ 授權紅線:必須 CINC Auditor(Apache 2.0),絕不可換官方 InSpec 6+ 商業 binary 或 inspec-core gem(均受 Chef EULA)。 路徑解析走 CINC_AUDITOR_CMD 環境變數比照 LibreOffice 慣例,不要硬編 /usr/bin/cinc-auditor

  2. POC 環境唯讀確認第 9 棒完成(純 SELECT,未動任何狀態)。上版前的基準值:

    環境 config.detection_tool_profiles 筆數 config.detection_profile% 新表數
    POC 存在 12 0
    STG 存在 10 0

    四支 migration 只套 DEV 的結論不變。上版時這兩組筆數就是「搬遷前應有幾筆」的對帳基準。

  3. .1 開工時機 — 已完成。拆表 migration 於 2026-08-03 套 DEV(d7cf9abc),DEV 驗收通過;STG/POC 那張服役中的表未被動過,改名風險尚未實際發生,上版時才會遇到。


§6 座標(收尾日實查,勿照抄 design.md)

FE(🔴 CM-1064 已大改,管理頁拆成一頁 + 六支子元件)

src/views/detection-profile/
├── DetectionProfileManageView.vue        961 行(原 1,239 → CM-1064 拆成 688 → CM-1078/1080/1084 後 961)
│     ├── pageSize = ref(20)              L77   ← 分頁預設(`247b6f5`,原 10)
│     ├── buildActionMenuItems(row)             主檔層 menu 組裝點
│     └── :rows-per-page-options="[10,20,50]"   L711  ← 改預設分頁時新值必須在此清單內
├── DetectionProfileControlsView.vue      632 行(控制項詳細頁)
├── profileDisplay.js                      顯示名解析共用
└── components/
    ├── ProfileFormDialog.vue             433
    ├── ProfileVersionTable.vue           431(CM-1084 +185/-21,版本列也收成 menu)
    ├── ControlExtractionSummary.vue      279
    ├── ProfileSourceDialog.vue           207  ← CM-1084 新增(修正來源對話框)
    ├── ProfileNewVersionDialog.vue       175
    ├── ProfileDetailDialog.vue           170
    └── ProfileCopyDialog.vue             149

src/composables/useProfileUsage.js                        122 行  ← CM-1084 新增(問判定 + 組訊息)
src/service/DetectionToolProfileService.js                243 行(CM-1084 +77,五支新方法)
src/components/detection-tools/DetectionConfigField.vue   269 行(下拉分組)
src/views/device/DeviceManage.vue
src/config/api/api.js                                     controls/extraction/taxonomies + CM-1084 四支端點常數
src/config/locales/i18n/{zh-tw,en}/detection-profile-manage.json   CM-1084 各 +21 條
src/config/locales/i18n/{zh-tw,zh-cn,en}/error-code.json          CM-1083 各 +3 條(409009~409011)

CM-1084 的三條 UX 規則(實作已落地,改這頁前務必先讀): ① 不可用的動作灰掉 + 說明原因,訊息要帶「被用了幾次 + 被哪些專案用 + 該怎麼辦」;專案清單為空但 in_use=true 時要自然降級成不帶專案名(不可印出空括號) ② 「刪除」與「停用」不同時出現——不是兩項都放然後刪除灰掉,而是只出現其中一項(未用過→刪除/用過→停用) ③ 刪除二次確認框要列出「將一併刪除 N 個版本、M 條控制項」的具體數字,不是只寫「確定刪除嗎」 ④ 判定拿不到時**保守當作「不能刪」**而非放行(判定回錯方向會刪掉不該刪的)

⚠️ 要改詳細頁的展開列,先讀 LOG 第 4 棒「PrimeVue 3 展開列會整個銷毀重建」那條——加 :key 或改具名函式 ref 都擋不住。

另一處事實更正:design.md §4.3 寫「orchestration 的三處呼叫點改指 get_version_with_profile()」,實查 _profile_domain.get_by_uid 只有兩處

  • app/detection_tools/service/detection_orchestration_service.py:224_load_profile(),破口①)
  • 同檔 :794_humanize_profile_param(),破口②)

建 T-1.4 卡時寫兩處。

再一處事實更正(2026-08-03,CM-1060 實查):design.md §8.1 寫「既有 10 筆 soft-ref 引用零轉換仍可解析」,這個描述不精確。實際形態是 job_execution_detection_tools.tool_params 那 4 筆 4/4 全部指向 profile 的 uid,但 agent_tasks.params 那 6 筆裡只有 2 筆(url 型)指向 profile 的 uid,另外 4 筆(file 型)的 _profile.uid 存的是 upload_files 的 uid、本來就不指向 profile 表。

寫迴歸測試時該斷言的是 6 筆tool_params 4 + agent_tasks.params url 型 2),file 型 4 筆走 upload_files 路徑要分開驗。已寫進 CM-1062 卡頭。

BE 檔案(🔴 舊的 detection_tool_profile* 命名已全數改為 detection_profile*

infra/detection_tools/model/       detection_profile{,_version,_control,_taxonomy}.py
infra/detection_tools/mapper/      detection_profile{,_version,_control,_taxonomy}_mapper.py
infra/detection_tools/repository/  detection_profile{,_version,_control,_taxonomy}_repo_impl.py
                                   detection_profile_usage_query.py     124 行  ← CM-1082 三來源 UNION ALL(find_refs)
domain/detection_tools/entity/     detection_profile{,_version,_control,_taxonomy}_{entity,query_entity}.py
domain/detection_tools/repository/ detection_profile{,_version,_control,_taxonomy}.py
                                   detection_profile_version_repo_impl.py  214 行(CM-1083 +49)
domain/detection_tools/service/    detection_profile_domain_service.py(含 get_version_with_profile;CM-1083 +41)
                                   detection_profile_control_domain_service.py
                                   detection_profile_taxonomy_domain_service.py
app/detection_tools/service/       detection_profile_service.py         1,119 行(CM-1082 +98/CM-1083 +171)
                                   detection_profile_taxonomy_service.py
                                   detection_profile_extraction_service.py
api/detection_tools/routes/        detection_profile_route.py            582 行(15 個 Resource)
                                   detection_profile_taxonomy_route.py
api/detection_tools/serializers/   detection_profile.py/detection_profile_taxonomy.py
common/util/profile_extractor/     __init__.py 71/base.py 95(註冊表+抽象基底)/inspec.py 439
common/util/safe_http_fetch.py     473 行  ← CM-1072 代下載(SSRF 五道防護)+ CM-1075 probe_url_validators()
common/util/detection_profile_ref.py    76 行  ← §4.4 確認零影響,未動
common/code/detection_tools_error_code.py    FR-060 共 13 條(CM-1083 +3:409009/409010/409011)
test/  test_detection_profile_{version_alloc,dispatch,taxonomy,archive}.py
       test_detection_profile_usage.py                                  204 行 11 條  ← CM-1082
       test_detection_profile_edit_delete.py                            367 行 19 條  ← CM-1083(+CM-1093 補 autouse patch logger)

scripts/sql/2026-08-03-fr060-1-detection-profile-split.sql              662 行
scripts/sql/2026-08-03-fr060-2-detection-profile-taxonomies.sql         272 行
scripts/sql/2026-08-03-fr060-3-param-schema-extraction-declaration.sql   91 行
scripts/sql/2026-08-04-fr060-3-dpv-source-validators.sql                 79 行  ← CM-1075(第四支)

CM-1082 新增的兩支唯讀端點(註冊在 /<string:uid> 之前,才不會被當成 uid 吃掉;沿用既有 referencing-* 命名慣例):

GET /api/1.0/detection-tool-profiles/<uid>/referencing-usage           主檔層
GET /api/1.0/detection-tool-profile-versions/<uid>/referencing-usage   版本層
回傳 {in_use, projects: [{uid, name}], version_refs}

app service 兩支方法:get_profile_usage() / get_version_usage()detection_profile_service.py,共用 _build_usage()); domain service 新增 list_all_versions()(不分頁,判定專用)。

🔴 _build_usage() 有一條 fail-open fallbackif self._usage_query is None: return {"in_use": False, ...}),會讓「守門有效」與「守門根本沒被呼叫」在測試裡長得一模一樣。DI 已 wiring,真實環境不會走到;但寫新的守門測試時必須斷言 in_use=true 那條路徑確實走到,不可 mock 掉 usage_query

CM-1083 新增的三支寫入端點

PATCH  /api/1.0/detection-tool-profile-versions/<uid>/source   改來源(版號不動、重抽控制項)
DELETE /api/1.0/detection-tool-profile-versions/<uid>          刪版本(非 current 且未使用過)
DELETE /api/1.0/detection-tool-profiles/<uid>                  刪主檔(硬刪,CASCADE 帶走版本與控制項)

三個 error code(common/code/detection_tools_error_code.py):

常數 代碼 用途
DETECTION_PROFILE_VERSION_IN_USE DETECTION_TOOLS_409009 版本已被使用過,不可改來源/刪除
DETECTION_PROFILE_IN_USE DETECTION_TOOLS_409010 主檔底下有版本被使用過,不可刪除
DETECTION_PROFILE_CURRENT_VERSION_UNDELETABLE DETECTION_TOOLS_409011 不可單獨刪除當前版本

🔴 沒有任何「強制執行」參數或旗標可以繞過 409——已被使用過的版本一律凍結,這是決策者裁定的稽核可信度問題,不是 UX 取捨(不提供「確定要更新嗎」的硬改選項)。 無新 migration:CASCADE 在 FR-060.1 拆表時就已設好。

CM-1077 三張子卡的派工內容(第 7 棒產出 c3b10b32,第 9 棒上 Notion)

docs/features/FR-060-2608-detection-profile-content-management/cards/
├── CM-1077-1-usage-judgement.md    202 行  → Notion CM-1082(✅ 已實作 `17e977eb`)
├── CM-1077-2-edit-and-delete.md    235 行  → Notion CM-1083(✅ 已實作 `dddfe7cf`;第 9 棒 185→235 補「前置卡 .1 提供的介面」節)
└── CM-1077-3-fe-actions.md         193 行  → Notion CM-1084(✅ 已實作 FE `88f2e13`)

三份都自足到「新 session 不讀其他文件就能開工」,含 DEV 實測值可直接當驗收斷言。 .2 卡經第 9 棒擴充後,決策者拍板的四節(規則/邊界/作業紀律/改完要能重抽)未動,只追加前置介面與第 13 條完成定義。


§7 三個必讀陷阱(來自母卡,實作時逐條對照)

① 人工待判項判準必須是 impact == 0.0

tags.check_type == 'pending'漏 6 條twgcb_01_014_0079~0084check_type: 'service' 但實為 impact 0.0 且只有 skip)。impact 是 InSpec 原生語意,外來 profile 也一定有。不要依賴任何自訂 tag 做這個判定。

⚠️ 但表欄位名不叫 impact(D19)——用 severity_rawseverity_norm,判準寫在各格式的 extractor 裡。

② 派工鏈兩處破口(原以為零影響,實 grep 推翻)

  • 破口① _load_profile()is_active 守門——拆表後在主檔。從檔 entity 有屬性但預設 None 則 None is False 為假 → 守門靜默失效、已停用的 profile 照樣派得出去(無聲授權漏洞,比 500 更糟)
  • 破口② _humanize_profile_param()getattr(profile,"name",None) 有 default 不報錯,只讓通知信「掃描設定」靜默退化成 profile:<uuid>,且目前無任何測試會抓到
  • 解法:domain service 新增 get_version_with_profile(uid) 回主+從合成 entity

③ 「STG 跑得順」不能當驗收依據

STG 的 10 筆全 SYSTEM、無 TENANT。搬遷 SQL 在 STG 測不到租戶路徑、測不到 32/33 三欄 JOIN 陷阱、測不到停用列造成的孤兒主檔驗收必須在 DEV 做。


§8 冷接自檢題(答不出來代表沒讀懂,回頭讀)

  1. 為什麼一個「瀏覽 profile 內容」的需求要順帶拆資料表?(提示:唯一索引拿什麼當身分)
  2. 搬遷時舊表那 13 個 uid 要給主檔還是從檔?為什麼?
  3. 從檔為什麼一定要自己掛 RLS,不能靠主檔的 FK 繼承?
  4. 為什麼「STG 跑得順」不能當驗收依據?
  5. 本案至今寫過幾行 production code?

答案分散在 §1、§2、§7,以及 CM-1054 母卡的 D3/D4 段。