| 項目 | 內容 |
|---|---|
| 緣由 | Bug B 收尾後 user retry docx import,發現 mf template-edit「外部利用服務 (1)」但預覽顯示 4 筆。BE 寫了 1 筆,漏 3 筆 |
| Branch | feature/ssp-oscal-alignment(兩 repo 一致,user 已 push 到 origin) |
| Source mf | 5eb137c8-84b6-4894-b0dd-a25ae092a8d2 (id=368);SSP shell id=266 |
| 接手前必讀 | 本文件自包含 — 不必另開其他 prompt;按 §0 順序讀本檔 + reference 文件即可 |
| 預估時間 | 1.5-3 小時(追 v2-bundle confirm 完整 path + DB / FE 雙端 verify) |
2026-05-25-bug-b-FIXED-SUMMARY.md — Bug B 兩段 fix 收尾 + 教訓(必讀,避免回頭追 Bug B;以及學 silent-failure pattern 教訓)design.md §11.17 + §11.18 + §11.22~§11.24 — Bug A SspShellService 拆分 / v2-bundle confirm 整體流程 / Bug B 兩段 reconciliationapp/oscal/service/ssp_docx_import_app_service.py:_run_v2_bundle_confirm (~line 703) — Bug D 主嫌路徑SspImportConfirmService.confirm 實作(grep 找)— LA / Component / Inventory write 核心讀完後跑 §6 Pre-flight + §7 Verify Bug B → §3 Verify root cause 候選 → §4 開工順位。
mf 5eb137c8 template-edit 「外部利用服務」tab 顯示 (1) — 1 筆「MDR、病毒碼與威脅情資同步更新」。但 docx 匯入預覽「外部利用服務 (4)」— 4 筆。寫了 1 筆,漏 3 筆。
SET app.is_super_admin='t')-- mf 368 → profile 134 → ssp 266
SELECT id, oscal_profile_uid FROM public.module_frames
WHERE uid='5eb137c8-84b6-4894-b0dd-a25ae092a8d2';
-- id=368, profile_uid='ad02f785-...'
SELECT id FROM oscal.profiles WHERE uid::text='ad02f785-fab0-45b7-91e7-ca80ac0ea0e8';
-- profile_id=134
SELECT id, uid::text FROM oscal.system_security_plans WHERE profile_id=134;
-- ssp id=266, uid='10829f1d-04f1-469c-988b-3d66e9e27040', status=draft
SELECT id, ssp_id, title FROM oscal.ssp_leveraged_authorizations WHERE ssp_id=266;
-- 20 | 266 | MDR、病毒碼與威脅情資同步更新 ← 只 1 筆,預期 4 筆{
"decisions": [...15 controls...],
"parties_decisions": [...5 parties...],
"manual_assignments": [],
"skipped_paragraph_idxs": [],
"predicted_controls_user_selection": [...],
"source_uid": "5eb137c8-84b6-4894-b0dd-a25ae092a8d2",
"content_overrides": {}
}完全沒有 leveraged_services / leveraged_authorizations 欄位。BE 寫的 1 筆是 _run_v2_bundle_confirm 從 parse_job.parsed_result 自動寫的(不靠 FE 決策),但只寫 1 筆 — 4 筆少了 3。
Bug B 從 2026-05-20 追到 2026-05-25,跨 2 sessions / 5 天才完整 close。本期 Bug D 別重複以下錯誤:
parties_written=5 騙了兩段時間,root cause 在 _upsert_responsible_party silent-skip 卻沒在計數體現。Bug D fix 後必查 DB ssp_leveraged_authorizations 真有 4 筆,不要相信 BE log 的 caller 計數。confirm_service.confirm() 是否有同樣症狀 — 若 Excel OK,比對兩條 path 找 docx 偏差。/module-frame/import-docx 是 create mode,wizard 跳 Step 3,預覽用 LeveragedSection.vue 不是 diff stepper。該追的 path:
| 步驟 | 檔案 / 行號 | 該看什麼 |
|---|---|---|
| 1 | ssp_docx_import_app_service.py:_run_v2_bundle_confirm (~line 703) |
source_type='module_frame' branch 走 ssp_shell_service.ensure_shell → confirm_service.confirm(ssp_id=...) |
| 2 | 找 SspImportConfirmService.confirm 實作 |
處理 LA / Component / Inventory write 的邏輯;leveraged 是否依賴 catalog_id?line 749-755 註解說「catalog_id 是 None — orchestrator's catalog-scoped reconcilers skip gracefully」— 可能 reconciler 過濾掉 3 筆 |
| 3 | bundle.parsed_leveraged_authorizations 從哪填 |
docx adapter app/oscal/service/ssp_docx_import_app_service.py:424 _convert(asdict(la)) for la in bundle.parsed_leveraged_authorizations — 找 bundle build 處 |
| 4 | parsed_ssp.leveraged_services vs bundle.parsed_leveraged_authorizations |
兩個概念可能不同 — FE 預覽 4 筆是哪個 source?BE 寫 1 筆是哪個 source? |
| 5 | BE log 完整 confirm trail | grep "v2-bundle|written_las|confirm_service|Docx v2-bundle confirm" log/app.log |
Verify A:
# A1: 查最近 parse_job 內 parsed_result 的 leveraged 結構
PGPASSWORD='jedi@123!' psql -h 192.168.50.188 -p 25432 -U cmmgr -d guidant_ai_dev -c "
SET app.is_super_admin='t';
SELECT id, status,
jsonb_array_length(COALESCE(parsed_result->'leveraged_services', '[]'::jsonb)) AS lev_svcs,
jsonb_array_length(COALESCE(parsed_result->'leveraged_authorizations', '[]'::jsonb)) AS lev_auths
FROM oscal.parse_jobs
ORDER BY id DESC LIMIT 5;
"
# 解讀:
# - lev_svcs=4 + lev_auths=1 → A2 adapter 把 4 services 縮成 1 authorization(候選 A 成立,上游 adapter bug)
# - 兩者都 4 → confirm_service 寫入時擋掉 3(候選 A 成立,下游 write bug)
# - 兩者都 1 → docx parser 抽錯 / dedup(更上游 extractor bug)
# A2: 查 ssp 266 完整 confirm 寫入路徑 BE log
grep -E "ssp_id=266|leveraged|v2-bundle|written_las|written_components|reconciler" \
~/Projects/Billows/Audit-Manager/compliance-manager-be/log/app.log | tail -50該追的 path:
| 步驟 | 檔案 / 行號 | 該看什麼 |
|---|---|---|
| 1 | compliance-manager-fe/src/components/grc/ssp-docx-import-v2/SspDocxImportPage.vue onConfirm (~line 500-610) |
看是否該組 leveraged_decisions / leveraged_services_decisions 進 payload |
| 2 | compliance-manager-fe/src/components/grc/ssp-docx-import-v2/sections/LeveragedSection.vue |
預覽顯示 4 筆的元件 — 有沒有 user decision UI? |
| 3 | compliance-manager-fe/src/stores/sspDocxImportStore.js |
看 store 有沒有 decisions.leveraged_services 結構 |
| 4 | BE confirm schema | 看 _validate_decisions 等是否預期收 leveraged 欄位 |
Verify B:
grep -rn "leveraged_services_decisions\|leveraged_decisions\|decisions.leveraged" \
~/Projects/Billows/Audit-Manager/compliance-manager-fe/src/
# 完全沒 hit → 候選 B 成立(FE 從沒實作 leveraged 決策)
grep -n "props.leveraged\|leveraged_services\|emit.*update" \
~/Projects/Billows/Audit-Manager/compliance-manager-fe/src/components/grc/ssp-docx-import-v2/sections/LeveragedSection.vue直覺:候選 A 概率較高。理由:
content_overrides={} 是空的(FE 預設 — 邏輯上 leveraged services 應該透過 content_overrides.leveraged_services 傳,但 user 沒編輯所以空)confirm_service.confirm() — Excel 端可能 OK 或同樣有 bug,cross-source check 必跑但也不排除 A + B 混合:FE 該支援 leveraged decisions 但沒做,BE 寫入也有 bug。
SspImportConfirmService.confirm 內 LA write 邏輯,找出 3 筆被擋的條件ssp_leveraged_authorizations WHERE ssp_id=<new_ssp> 真有 4 筆才算 done。不要相信 BE log 的 caller 計數(§2.1 教訓)2026-05-25-bug-b-FIXED-SUMMARY.md)| 檔案 | 為何 read |
|---|---|
app/oscal/service/ssp_docx_import_app_service.py:_run_v2_bundle_confirm (~line 703) |
confirm path 入口,看 catalog_id=None 是否影響 LA write |
app/oscal/service/ssp_docx_import_app_service.py:424 附近 |
bundle.parsed_leveraged_authorizations build 處 |
SspImportConfirmService.confirm 實作(grep 找) |
LA / Component / Inventory write 核心邏輯 |
app/oscal/service/ssp_excel_import_app_service.py:_run_v2_bundle_confirm (~line 1602) |
Excel 走同一 confirm_service — 看 Excel 有沒有踩 Bug D(cross-source check) |
| 檔案 | 為何 read |
|---|---|
compliance-manager-fe/src/components/grc/ssp-docx-import-v2/SspDocxImportPage.vue:500-610 |
onConfirm 組 payload 處,看有沒有 leveraged_decisions |
compliance-manager-fe/src/components/grc/ssp-docx-import-v2/sections/LeveragedSection.vue |
預覽顯示 4 筆 leveraged 的元件 |
compliance-manager-fe/src/stores/sspDocxImportStore.js |
看 decisions 結構是否有 leveraged |
compliance-manager-fe/src/composables/useSspLeveraged.js |
leveraged 相關 composable(如果有) |
跨 repo 改 FE 前必 read ~/Projects/Billows/Audit-Manager/compliance-manager-fe/CLAUDE.md(per memory feedback_cross_repo_read_claude_md_first)。
# 1. 兩 repo branch
git -C ~/Projects/Billows/Audit-Manager/compliance-manager-be branch --show-current
git -C ~/Projects/Billows/Audit-Manager/compliance-manager-fe branch --show-current
# 預期:兩個都 feature/ssp-oscal-alignment
# 2. 兩 repo working tree
git -C ~/Projects/Billows/Audit-Manager/compliance-manager-be status --short
# 預期:M pyproject.toml only (dev path-dep,永不 stage)
git -C ~/Projects/Billows/Audit-Manager/compliance-manager-fe status --short
# 預期:clean
# 3. local vs origin(user 已 push)
git -C ~/Projects/Billows/Audit-Manager/compliance-manager-be log origin/feature/ssp-oscal-alignment..HEAD --oneline | wc -l
# 預期:0
git -C ~/Projects/Billows/Audit-Manager/compliance-manager-fe log origin/feature/ssp-oscal-alignment..HEAD --oneline | wc -l
# 預期:0
# 4. BE 是否有重啟接 Bug B 第二段 fix (fef5eecf)
lsof -t -i:8000 # 若有 listener,pid → ps -o lstart -p <pid> 看啟動時間
# 若 BE 還沒接 fef5eecf 重啟一次:
# lsof -t -i:8000 | xargs -r kill -9 && python main_socketio.py
# 5. BE test smoke
poetry run pytest tests/test_ssp_docx_import_app_service.py -q
# 預期:全綠PGPASSWORD='jedi@123!' psql -h 192.168.50.188 -p 25432 -U cmmgr -d guidant_ai_dev -c "
SET app.is_super_admin='t';
SELECT id || ' role=' || role_id || ' party=' || party_uuid::text
FROM oscal.oscal_responsible_parties
WHERE context_type='module_frame' AND context_id=368;
"
# 預期 5 筆 (id 216-220):
# 216 role=responsible-organization (org)
# 217-220 role=system-user (4 person)如果 5 筆都在 → Bug B close,繼續 Bug D。 如果 0 筆 → Bug B 沒 close(不該發生但 verify 一下),先回頭挖 §11.22 / §11.24 是否被誰 revert。
feedback_no_branch_switch)feedback_stage_commit_no_ask)feedback_cross_repo_read_claude_md_first)feedback_be_restart_after_service_change,BE 沒 hot reload)feedback_jedi_package_dev_path_first,dev 階段不每改必 bump version)feedback_no_chinglish — 動詞 / 連接詞用中文,技術專有名詞保留英文)feedback_plan_vs_reality_verify_first)handoff/2026-05-25-bug-d-FIXED-SUMMARY.md 寫短收尾報告(mirror 2026-05-25-bug-b-FIXED-SUMMARY.md 樣式:root cause / commits / DB verify / 教訓 / 殘留)_upsert_responsible_party silent-skip cleanup(列 jedi 進版時做)fc51dd08) 失敗 import 殘留清理(無害,user 可自行刪)origin/feature/ssp-oscal-alignment 已包含(user 已 push):
BE:
4441d3f4 docs(ssp-oscal-alignment): Bug B 收尾 SUMMARY + Bug D handoff
fef5eecf fix(ssp-oscal-alignment): Bug B 第二段 — docx _dict_to_parsed_parties 補 default role
ba7885d4 docs(ssp-oscal-alignment): design §11.22 + §11.23 — Bug B + Issue 1 reconciliation
8648940d docs(ssp-oscal-alignment): fix phase4 SUMMARY §5 L7 drift — Bug B 改現在優先 fix
375236a9 docs(ssp-oscal-alignment): Bug B + parties stepper handoff for next session
FE:
f31d0cf fix(ssp-oscal-alignment): Bug B parties default decision + Issue 1 缺欄位 render
更早的 Phase 4 task arc commits (BE 34 + FE 5) 也已 push。
接手 SSP OSCAL Alignment Bug D — docx import 4 leveraged services 只寫 1
筆。完整 context 全在
docs/features/FR-028-2605-ssp-oscal-alignment/handoff/2026-05-25-bug-d-leveraged-services-handoff.md
按本檔 §0 接手讀序執行 — 必跑 §6 Pre-flight + §7 Verify Bug B → §3 verify
候選 → §4 開工。注意 §2 前次教訓 + §8 行為規範。前次 (Bug B 兩段) 已 close。