# FR-045 CMMC v2.13 PDF parser 相容性修正 — 收尾 SUMMARY

> Date: 2026-07-04 · 實作 + E2E 驗收 + 收尾
> 狀態：**完成並驗證**（四檔 E2E 過、套件測試 62 passed）。已隨 jedi-oscal-v2 2.2.0 發版。
> 手測待辦見末段。

## 一句話

讓 jedi-oscal-v2 的 CMMC parser 單一 adapter 同時解析 2021 舊版與 2024 v2.13 新版的
L1/L2 Assessment Guide（四份 PDF），解掉編號換制、疊字、上標註腳污染四個 root cause。

## Commits（全在 jedi-oscal-v2，branch `feature/FR-044`）

| commit | 型 | 主題 |
|---|---|---|
| `b590350` | feat | practice regex 雙格式（FAR 式 `AC.L1-b.1.i`）+ `[FCI/CUI Data]` 標題尾綴剝除 |
| `bc6d842` | fix | PDF 行抽取字型分流（Cambria-Bold 標題 vs Cambria 內文，解同 y 疊字）|
| `de96b91` | fix | TOC 噪音過濾豁免結構標題（上標註腳污染 `POTENTIAL` 標題致 methods 全空）|
| `a4bd497` | fix | 字級過濾去上標污染（`_MIN_CONTENT_SIZE=11.0`，解「system 45」切碎）|
| `5245f29` | chore | jedi-oscal-v2 2.2.0 發版（FR-044 session 帶出，含 FR-045）|

## 改動範圍

- **只動兩檔**：`jedi_oscal_v2/infra/adapter/cmmc/cmmc2_lv2_parser_adapter.py` +
  `tests/catalog/test_cmmc_pdf_parser_v213_compat.py`（新增，30 條 unit）。
- **BE 零程式碼改動**（本案是 package-only）。BE 端只有本收尾文件（changelog / analysis /
  本 SUMMARY）。
- 新增模組級：`_PRACTICE_PATTERN` / `_PRACTICE_CODE_PATTERN` / `_NEXT_PRACTICE_ID_PATTERN`
  / `_TITLE_DATA_SUFFIX` / `_FAR_ID_NORMALIZE` / `_normalize_practice_id()` /
  `_is_toc_noise()` / `_MIN_CONTENT_SIZE`。class 內新增 static `_merge_font_streams()`。

## 行為差異（修正前 → 後）

| 檔案 | 修正前 | 修正後 |
|---|---|---|
| L1 v2 | practices=**0**（全滅） | practices=**15**、AO/methods 正常 |
| L2 v2 | 假成功：AO 遺失 68 條、methods 分桶 1518/10/10（毀損）| 110 practices、AOs=320、分桶 979/361/217 |
| L1/L2 舊版 | 正常 | **逐條零差異**（字型/字級過濾對舊版透明）|

## 規範文件清單（本次收尾產出）

- ✅ changelog：`docs/changelog/2026-07-04-fix-fr045-cmmc-v213-parser-compat.md`
- ✅ analysis：`docs/analysis/2026-07-04-cmmc-v213-parser-compat.md`（4 root cause + 4 設計決策 + 反悔條件 + interview/test 發現）
- ✅ SUMMARY：本檔
- ✅ README FR-045 列：plan 階段已登記（`docs/features/README.md:98`）
- ✅ memory：`feedback_cmmc_pdf_superscript_footnote_pollution.md` + `followup_cmmc_interview_test_not_persisted.md`

## 已知 follow-up

1. **Interview / Test 不會存進系統**（重要）：parser 正確解析三桶，但 BE `_tree_to_dict`
   （`app/oscal/service/framework_parse_job_service.py:429-437`）刻意只保留 `EXAMINE` →
   `guidance`（還原 V1 行為）。要讓 interview/test 落地、FE 看得到，需獨立 BE 改動
   （`_tree_to_dict` 帶出三桶 → `_persist_catalog` 寫成 assessment-method part → FE/staging
   schema/confirm 對應）。資料模型已支援（`oscal_catalog_control_part.props`）。屬新需求決策，
   等 user 拍板是否開 FR。詳見 analysis §5。
2. **L3 guide 未支援**：本案 scope 只有 L1/L2 四檔；L3（`*.L3-` / 800-172）另案。

## 部署 handover

- jedi-oscal-v2 2.2.0 已發版（Nexus），BE `pyproject.toml` 的 pin 由 FR-044 session 管理。
- **BE 無 hot reload**：要從 UI 驗證需重啟 BE。
- 資料修復：若 DB 已有用 v2 檔匯過的殘缺 catalog，屬另一資料修復任務（先確認是否存在）。

## 手測 checklist（BE 重啟後）

- [ ] `/compliance-framework/import-version` 上傳新 L1 v2.13 → parse 預覽出 **15** 條 practice
- [ ] 新 L1 `AC.L1-b.1.i` 的 Guidance（Examine）出現完整「system security plan」、無「system 45」、
      無「…associated security plan documentation」錯位
- [ ] 新 L2 v2.13 → 110 條、methods 不空
- [ ] 舊 L1/L2 匯入行為與修正前一致（回歸）
