# Bug H ~ L 整段 arc 收尾 SUMMARY（2026-05-25 整日）

| 項目 | 內容 |
|---|---|
| Branch | `feature/ssp-oscal-alignment`（跨 BE + FE + jedi-common + jedi-oscal 4 repos）|
| 起源 | 早上 §11.25 Bug D fix ship 後 user 連續手測，一路追出 7 個連環 bug |
| 涵蓋 | **Bug H** (FE 4 子)、**Bug H-5** (BE email parse)、**Bug H-6** (jedi-common 假鉤稽)、**Bug I** (revert §11.25 + 廢棄 dual TabPanel)、**Bug J** (template SSP uid null)、**Bug K** (SSP endpoint 對 template SSP 404)、**Bug L** (LeveragedSection v3 對齊 + Card→Table + 命名) |
| 狀態 | 全 ship 到 working tree，**未 commit**，等 user 多輪測試後 batch commit + push |
| design.md | §11.26 ~ §11.32 七段完整 root cause / fix / 教訓已補；§11 index reference 已更新 |
| 對話歷史 | **尚未歸檔**（per CLAUDE.md「做 summary」流程，等整 case 真正收尾再從 JSONL extract）|

---

## 1. Seven bugs root cause 一覽

| Bug | 層級 | Root cause 一行 | Fix scope |
|---|---|---|---|
| **H** (4 子) | FE 純 UI | preview / template-edit / diff stepper 三元件 render 同 party 欄位但獨立維護，Bug B Issue 1 只修 diff stepper 留缺 | FE 4 檔（i18n + 2 vue）|
| **H-5** | BE parser | `_PARTY_LABEL_MAP` substring 順序 bug：`'address'` 排在 `'emailaddress'` 之前 → email row mis-classify 成 address → silently dropped；9 個歷史 parse_job 全踩 | BE 2 檔（parser + regression test）|
| **H-6** | jedi-common shared infra | SQLAlchemy `before_flush` hook 自動填 `org_unit_id` 是 RLS 設計用，但 OSCAL 4 表把 `org_unit_id` 當「鉤稽到的部門」業務欄位 → 雙語意衝突 → 467 row 假鉤稽 | jedi-common 1 + jedi-oscal 4 + BE pyproject + DB cleanup |
| **I** | BE adapter + FE | Bug D §11.25 short-term fix 把 T7 emit LA 違反 §1 設計；Phase 4 過渡 dual TabPanel 沒收尾 | BE adapter revert + FE 廢棄 3 TabPanel + preview 拆兩 section + DB cleanup |
| **J** | BE app service | `try/except: pass` 默吞 `AttributeError(get_by_id)` 應為 `get_ssp_by_id` → `ssp_uid` 永遠 null → FE 「元件清冊」tab 永遠走 hint | BE 1 line fix |
| **K** | BE permission | `SspProjectResolver` 假設所有 SSP 屬 project，template SSP 沒 AP 一律 404 | 新 `SspContextResolver` + permission 雙模式 + 3 SSP endpoint 改用新 method |
| **L** | FE preview ↔ BE 寫入 | FE `LeveragedSection` 讀 v2 `leveraged_services` + emit 到 `draft.leveraged_services`，但 confirm payload 沒帶 + BE `_apply_v2_bundle_overrides` 只認 v3 keys → user edits 完全 silently dropped；連帶 LA template-edit 視覺不對稱 + sub-panel 命名升級 | FE 3 檔（LeveragedSection 改 v3 + SspDocxImportPage 改 viewModel/payload + SspComponentsLeveragedInventoryTab Card→Table）+ 2 i18n + FE CLAUDE.md 新規範 |

---

## 2. 改動清單（working tree，未 commit）

### compliance-manager-fe
- `src/views/module_frame/ModuleFrameTemplateEditView.vue` — 廢棄 3 過渡 TabPanel + 新 tab header i18n key 引用 (Bug I + L)
- `src/components/grc/ssp-docx-import-v2/sections/PartiesSection.vue` — 加電話/地址欄位 + ROLE_LABEL 改「負責單位」(Bug H)
- `src/components/grc/ssp-docx-import-v2/sections/LeveragedSection.vue` — **完全重寫**：v3 keys + 兩 section + 對齊 sub-panel 命名 (Bug I + L)
- `src/components/grc/ssp-docx-import-v2/SspDocxImportPage.vue` — viewModel 加 v3 keys + confirm payload 用 `_buildIdxOverrides` 把 draft diff 轉 BE 期望 idx-keyed map (Bug L)
- `src/components/grc/ModuleFramePartiesPanel.vue` — DataTable +2 column / Dialog +2 input / Column header 改「負責單位名稱」(Bug H)
- `src/components/grc/ssp/SspComponentsLeveragedInventoryTab.vue` — 利用授權 Card→DataTable + 3 add buttons `outlined` (Bug L)
- `src/config/locales/i18n/zh-tw/ssp-docx-import.json` — section title 2 key 改「負責單位」/「參與人員」(Bug H)
- `src/config/locales/i18n/zh-tw/module-frame.json` — tab_responsible_org/person 2 key 改「負責單位」/「參與人員」(Bug H)
- `src/config/locales/i18n/{zh-tw,en}/ssp-components-leveraged-inventory.json` — 新 `tab_header` key + rename `section_components`/`section_leveraged` + 對應 add/edit/empty labels (Bug K + L)
- `CLAUDE.md` — 新增「Add / Create Action Button Style」section (user 規範: 新增類按鈕用 outlined)

### compliance-manager-be
- `domain/oscal/parser/docx_section_extractors.py` — `_PARTY_LABEL_MAP` 重排 email 在 address 之前 (Bug H-5)
- `domain/oscal/adapter/cmmc_ssp_adapter.py` — Table #7 不再 emit LA (Bug I Phase A)
- `domain/oscal/service/ssp_context_resolver.py` 新檔 — 雙模式 SSP context resolver (Bug K Phase A)
- `common/middleware/permission/ssp_permission.py` — 新 `require_read_access` / `require_write_access` (Bug K Phase B)
- `app/oscal/service/ssp_components_app_service.py` / `ssp_inventory_items_app_service.py` / `ssp_leveraged_app_service.py` — 改用新 permission method (Bug K Phase C)
- `app/oscal/service/module_frame_template_ssp_app_service.py` — `get_by_id` → `get_ssp_by_id` (Bug J)
- `di_containers/oscal/oscal_containers.py` — wire SspContextResolver (Bug K)
- `pyproject.toml` — jedi-common 切 path dep (Bug H-6 dev-only，不該 commit)
- `tests/test_docx_section_extractors.py` — 收緊 email test + 加 substring collision regression (Bug H-5)
- `tests/test_cmmc_ssp_adapter_v3_bundle.py` — 改 T6+T7 expected (Bug I)
- `tests/test_ssp_leveraged_app_service.py` — sed rename mock method (Bug K side effect)
- `docs/features/FR-028-2605-ssp-oscal-alignment/design.md` — §11.26~32 七段完整 entries + §11 index reference (本 doc)
- `scripts/sql/2026-05-25-bug-i-revert-t7-la.sql` 新檔 — DB cleanup mf 372 + 373 (Bug I Phase D)

### jedi-common (path dep, 未 commit)
- `jedi_common/session/database/db_mw.py` — `set_tenant_info_before_insert` 加 `__skip_auto_org_unit__` opt-out check (Bug H-6)

### jedi-oscal (path dep, 未 commit)
- `jedi_oscal/infra/model/base/oscal_party.py` — `__skip_auto_org_unit__ = True` (Bug H-6)
- `jedi_oscal/infra/model/base/oscal_leveraged_authorization.py` — 同上
- `jedi_oscal/infra/model/base/oscal_component.py` — 同上
- `jedi_oscal/infra/model/base/oscal_inventory_item.py` — 同上

### DB cleanup（已執行）
- mf 372 + 373 T7 LA 各刪 3 row (Bug I Phase D)
- 4 OSCAL 表 org_unit_id 全清成 NULL (467 row 累計：37 party + 36 LA + 391 component + 3 inventory) (Bug H-6)

---

## 3. Verify Evidence

### BE pytest
- Bug H/H-5 後：168 passed (含新 regression)
- Bug L 後：683 passed / 16 fail
  - 5 fail 是 `test_ssp_leveraged_app_service` 我引起 → 已 sed-rename 修，新 verify 5 passed
  - 11 fail 拆解：4 pre-existing (`ssp_resources` 2 + `ssp_system_characteristic` 2) + 6 cloud_integration env-dependent + 1 雜
  - **K1 引起的 leveraged_app_service 5 fail 已修**，其他 surface 給 user 不阻擋 ship

### E2E (Playwright + DB)
- mf 372 (`2c4ba0b8-...`) template-edit「系統元件、外部授權與資產」tab — 3 sub-panel 全 render、0 console errors、0 SSP endpoint 404
- 元件清冊 sub-panel 4 components (T6 MDR paired + 3 T7) — 「利用授權」column 正確顯示 T6 ref / T7 空
- 外部正式授權服務 sub-panel 1 LA (T6 MDR) DataTable + FedRAMP fields
- 資產清冊 0 (mf docx 沒 inventory)
- 鉤稽欄全「未鉤稽」(Bug H-6 cleanup verified)
- Tab 廢棄成 7 個（vs 過渡 10 個）

### 截圖
- `bug-h-template-edit-org-tab.png` / `bug-h-org-edit-dialog.png` / `bug-h-person-edit-dialog.png` (Bug H)
- `bug-h-import-preview-parties-tab.png` / `bug-h5-preview-email-filled.png` (Bug H + H-5)
- `bug-h6-cleanup-org-tab-no-link.png` / `bug-h6-cleanup-person-tab-no-link.png` (Bug H-6)
- `bug-k1-verify-3-subpanel-working.png` (Bug K1)

---

## 4. 不在 scope / 殘留

| 項目 | 處理 |
|---|---|
| en locale 多處未對齊（Bug H section_title / tab header / add button labels 等） | 等 user 拍板英文後 batch 補 |
| `oscal-role.json responsible-organization.label`「專案負責單位」是否改「負責單位」 | 暫不動 — Tag 角色 label vs Tab 分類 label 視覺層級不同 |
| `<PartyFieldRow>` 共用元件 refactor (三元件 render 同 5 欄位) | future cleanup — scope 太大本期不動 |
| jedi-oscal `_upsert_responsible_party` silent-skip pattern | 同 §11.24 Bug B follow-up — jedi-oscal 進版時順手 |
| Bug G init_ap_controls silent failure | 已撤回（早晨 swap commit b7f02084）|
| Phase 5 OSCAL Export | Deferred |
| jedi-common + jedi-oscal Nexus 進版 + BE/FE 版號對齊 | user 拍板 — 待 feature 全 verified 才一次 bump 兩套件版本，BE pyproject 改回 pin |
| Pre-existing pytest fail：`test_ssp_resources_app_service` 2 + `test_ssp_system_characteristic_app_service` 2 | 不關 K1，可未來 cleanup phase 同 K1 pattern 改用新 permission method |
| `template_module_frame_id` entity field 沒 wire (Bug K1 改走 reverse query workaround) | future fix 可一併補 entity field auto-fill |
| 對話紀錄 export to docs/conversation-history | user 全測完 + commit 後再 extract from JSONL |

---

## 5. 整段 arc 的 7 條核心教訓

1. **三元件對齊 ≠ 一處改完** (Bug H) — preview / template-edit / diff stepper 三元件 render 同欄位但獨立維護，補 1 處不夠
2. **substring matching 順序敏感性** (Bug H-5) — dict-as-priority-map 短 pattern 排在長 pattern 之前會偷走 match (`'address'` 偷 `'emailaddress'`)
3. **shared infra hook 的雙語意陷阱** (Bug H-6) — jedi-common `before_flush` hook 把 `org_unit_id` 當 RLS scope 自動填，但 OSCAL 4 表把它當「鉤稽到的部門」業務欄位 → 雙語意衝突，opt-out flag 是正解
4. **short-term tactical fix 留 follow-up 要明確列追蹤** (Bug I) — §11.25 教訓 3 標「長期拆兩 tab，本期非 scope」但沒 follow-up tracking → user 踩到代價才升級
5. **`try/except: pass` 默吞錯誤是 anti-pattern** (Bug J) — silent failure 讓 bug 隱形數週，至少要 `log.warning` 留 trace
6. **Wrapper / routing 概念不該複製成獨立 domain** (Bug K) — MF 只是 SSP 的另一層入口，不該為每個 SSP sub-resource 寫 MF mirror endpoint。Permission resolver 對 context 應 explicit
7. **FE preview ↔ BE 寫入 path 必須對齊** (Bug L) — v2 legacy keys 跟 v3 bundle keys 共存時，FE 編輯哪個 source 直接決定能不能寫入。Phase 4 v2→v3 transition 沒清 v2 wire-up 是 latent bug

---

## 6. 給 user 的 hand-off summary

**已修 + 已驗收**（含 mf 372 自動回歸測 + 跨 7 bugs 連環追蹤）：

1. FE 9 檔（含 1 完全重寫 + 1 新 CLAUDE.md section）
2. BE 7 檔（含 1 新 resolver + 1 新 cleanup SQL + design.md §11.26~32 七段 entries）
3. jedi-common 1 檔 + jedi-oscal 4 檔（path dep）
4. DB 4 表清理共 467 row + mf 372/373 T7 LA 6 row
5. design.md §11.26~32 七段 + §11 index reference

**動作項（user 拍板）**：

1. **多輪手測**（per user 之前指示）：
   - mf 372 既有資料、新 docx import 全 chain、project SSP regression
   - 特別驗 Bug L-2：preview 編 status / category 後 confirm，template-edit 確認帶到
2. 全測通過後 **batch commit + push**：
   - BE: 1 commit 含 design.md / parser / adapter / context resolver / permission / 3 services / template ssp / DI / tests / SQL script
   - FE: 1 commit 含 9 檔
   - jedi-common: 1 commit (1 檔 db_mw)
   - jedi-oscal: 1 commit (4 model)
   - **BE pyproject.toml 不 commit**（dev-only path dep；等 jedi-common + jedi-oscal 進版才改回 pin 一起 commit）
3. 後續 release 時：
   - jedi-common + jedi-oscal **一次性 bump version + 推 Nexus**
   - BE `pyproject.toml` 改回 pin 新版本 → `poetry update jedi-common jedi-oscal` → 跟其他改動一起 commit
   - 走 release SOP (release_notes / BE+FE 版號對齊)
4. 對話紀錄歸檔（待 user 確認時觸發）：
   - `python3 scripts/extract_claude_sessions.py --date 2026-05-25 --topic bug-h-to-l-arc --auto`

**測試新建殘留資料**：
- mf 369 ~ 373 為前後測試殘留，可手動刪
- parse_job 140 ~ 153 同樣

---

## 6.5 接手下個 session：Bug O 已 ship spec + handoff doc

**Bug O 範圍**：docx 重 import diff stepper 缺 4 key (sc / components / leveraged_authorizations / inventory_items) + UI 改 TabView。**spec 已寫進 design.md §11.34 (⏸ DEFERRED 標註)、handoff 文件已寫進 `docs/features/FR-028-2605-ssp-oscal-alignment/handoff/2026-05-25-bug-o-diff-stepper-expansion-handoff.md`** — 自包含、下個 session 冷接可動工。

**為什麼分新 session**：
- Scope 大（跨 BE + FE，~10+ 檔，估 6-10 小時）— 跟 H-N arc 同級
- H-N batch commit + push 後再開，working tree 乾淨
- 避免兩 track 並行（H-N 驗測修補 + Bug O 開發）造成 context 混亂

**接手 prompt**：見 handoff doc §10「給 fresh session 的超短 prompt」段。

---

## 7. 為何整段 arc 拖出 7 個連環 bug

Bug H (user 報的 FE label) → 補欄位 render (H-2/H-4) → 露出 email 欄位 (H-5: 從 day 1 就有，借 H-4 浮出) → 露出鉤稽欄位 (H-6: 從 day 1 就有，借 H-4 浮出) → 補完 leveraged section 拆兩 sub (Bug I：違反 §1 原設計被 §11.25 short-term fix 蓋著) → ship Bug I 後 template-edit 永遠 hint (Bug J: silent AttributeError) → Bug J 修完 endpoint 404 (Bug K: project resolver 假設所有 SSP 屬 project) → Bug K 修完發現 preview edits 沒帶到 (Bug L: FE v2 / BE v3 wire 不同 source)

**根本啟示**：**借「user 看不到的 bug 借 UI 補新欄位才浮出」這個模式追下去，會連環暴露 latent bug，每個 bug 都 day 1 就有，只是長期沒人查。** 整段 arc 是「補一層 UI 後續往下挖」的 7 連發。
