本卡屬 FR-114 資安修正(母卡 CM-2019),b4 總測回報收集卡 CM-2231 #34。b4 回歸(CHECK 是 CM-2247 加的),高:任何客戶只要一版抽取失敗過一次,之後永遠抽不成功、沒有自動復原路徑。修 jedi-detection 套件。

問題是什麼(白話)

檢測基準的某一版抽取失敗後(190 上是 b3 時期「找不到 cinc-auditor」),錯誤訊息留在 extraction_error 欄。b4 補了 CINC 後重抽,CINC 有跑成功(log「成功 controls=59」),但寫回資料庫時只把狀態改成 succeeded、舊的錯誤訊息沒清掉,撞到 CM-2247 加的 CHECK chk_dpv_succeeded_no_error(succeeded 時 error 必須為空),整個 UPDATE 回滾,接著失敗路徑又把這次的約束錯誤寫進 error 欄。下次再重抽還是同樣結果,死循環。

為什麼清不掉:成功落庫走共用的 BaseRepositoryImpl.update(),它的欄位迴圈帶 value is not None——設成 None 的欄位會被靜默跳過(jedi-common base_repository_impl.py:424)。同一支 repo 的 replace_source() 早就知道這件事(repo_impl.py:164 註解「為什麼不能走 update()」,:190 直接對 model 清),成功落庫這條路徑漏了同樣處理。

首腦已核對的證據:190 config.detection_profile_versions id=1(url 型,dev-sec linux-baseline)在升級後重抽,api log 20:49:25 先「inspec._run:243 成功 controls=59」,35ms 後「_extract_in_thread:472 worker 未預期失敗」,SQL 是 UPDATE ... SET sha256, source_etag, extraction_status='succeeded'——參數裡沒有 extraction_error。190 該列已由首腦手動 SET extraction_error=NULL 解鎖(決策者核准);DEV 11 版從沒失敗過所以驗不到。

工作區

在哪裡

jedi_detection/app/service/detection_profile_extraction_service.py:611-635  _persist() 成功段:612 設 extraction_error=None,635 呼叫 update_version → 走共用 update() 被跳過
jedi_detection/app/service/detection_profile_extraction_service.py:649-656  _write_status():失敗路徑,同一支 update_version(error 寫 None 時同樣清不掉,例如 STATUS_RUNNING 進場)
jedi_detection/domain/detection_tools/service/detection_profile_domain_service.py:138-141  update_version() 直接 self._versions.update(entity)
jedi_detection/infra/detection_tools/repository/detection_profile_version_repo_impl.py:153-190  replace_source():既有「不走 update()、直接對 model 清欄」的範例
jedi_detection/domain/detection_tools/repository/detection_profile_version.py  version repo port(沒有 clear_fields;profile 那張表的 port 在 detection_profile.py:41 有)
主線 migration(BE 工作區)scripts/sql/2026-09-27-fr114-detection-profile-succeeded-no-error.sql  CM-2247 加的 CHECK,只清了 succeeded 帶 error 的列

怎麼修

要寫測試

屬核心共用邏輯(改 repo 寫入路徑),要寫。tests/integration/test_service_behaviour.py(需 Docker 起真 postgres,conftest 在同目錄)加一條:建一版 failed+extraction_error='x' → 跑成功落庫 → 斷言 status=succeeded 且 error IS NULL 且沒拋 IntegrityError。突變:把新方法改回走 update() 要紅(CHECK 會擋)。跑法 cd /Users/chouraymond/Projects/Jedicogy/module/jedi-python-package/.claude/worktrees/jedi-wt-fix-security/jedi-detection && PYTHONPATH=. python -m pytest tests/integration -q -k succeeded;整合測試起不來就跑 tests -q 契約測試並在回寫寫明打折。

手測