# SSP OSCAL Alignment — Phase 1 + Phase 2 FINAL SUMMARY — 2026-05-25

| 項目 | 內容 |
|---|---|
| Phase | **Phase 1 + Phase 2 COMPLETE** |
| 日期區間 | 2026-05-24（Phase 1 全日 + Phase 2 開工） ~ 2026-05-25（Phase 2 完工 + 收尾）|
| Branch（兩 repo 一致）| `feature/ssp-oscal-alignment` |
| Phase 1 完成 Tasks | 1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 14（11 / 14）— 跳 Task 10 E2E / Task 13 套件進版 |
| Phase 2 完成 Tasks | 1, 2, 3, 4, 5A, 5B, 5C, 6, 7, 8, 9, 11A, 11B（13 / 12 — Task 11 拆兩段執行）|
| 主專案 local commits | **30**（Phase 1: 14 + Phase 2: 14 + 收尾 hotfix: 2；全 local，未 push）|
| jedi-oscal local commits | **18**（Phase 1 全；Phase 2 + 收尾 hotfix 全在主專案）|
| 主專案 working tree | `M pyproject.toml`（Phase 1 Task 1 dev-only path dep，**永遠不 stage**；Task 12 Part 2 套件進版時才還原）|
| jedi-oscal working tree | clean |
| Dev DB | 4 新 OSCAL 表 + RLS (delimiter 修好) + 12 LA + 341 components + 0 inv_items；Docx import path 通；Excel import 走 legacy 412（見 §6.2）|
| 下一步 | **Phase 3 / Phase 4**（user 拍板「衝一下 3, 4」）— 詳見 `2026-05-25-phase3-4-handoff.md`；Task 12 Part 2 (jedi-oscal bump + push) 仍待 user 拍板 |

---

## TL;DR — Phase 1 + Phase 2 達成

✅ **Phase 1（Foundation）** — OLD 單一 `SspSystemImplementationItemEntity` 拆成 OSCAL-correct 3 entity（LeveragedAuthorization / Component / InventoryItem + M2M join），落地到 DB + jedi-oscal 套件 + 主專案 BE 全層。12 LA + 341 components migrate verified。18 主專案 callers refactor 完成，舊表 + 舊 M2M 全 DROP。

✅ **Phase 2（Import Pipeline 對接）** — Import pipeline 拆出獨立 module `domain/oscal/import_pipeline/`（warnings collector / normalizer / bundle_restore / confirm_service 四檔）；3 個 v3 write strategy（LeveragedWriteStrategy / ComponentWriteStrategy / InventoryItemWriteStrategy）落地；orchestrator 採 Minimal scope（只保留 leveraged reconcile）；Docx adapter 加 `adapt_to_bundle()` 輸出 v3；Docx app service 走新 pipeline 全通；Task 11 cleanup 刪 5 src + 4 test 共 1057 LOC dead code。

⚠️ **Excel parser gap（§6.2 / design.md §11.13）** — Excel app service dispatch 落地但 parser 還沒輸出 v2-bundle dict shape，目前 Excel import 走 legacy path → 412。**Phase 3 §3.X 接手**。

✅ Subagent-driven mode 跑通（13 個 Phase 2 task），review-after-implementer pattern 多次截到 spec drift（如 Task 11B reviewer 加 SourceTable enum）。

---

## 1. Phase 1 + Phase 2 Tasks 最終狀態

### Phase 1（14 tasks）

| # | Task | Status |
|---|---|---|
| 1 | 主專案 pyproject.toml path dep | ✅ 落地（dev-only, M pyproject.toml）|
| 2-4 | jedi-oscal PR-1/2/3（LA / Component / Inventory）| ✅ SHIPPED |
| 5 | ParsedExcelEntityBundle restructure | ✅ SHIPPED |
| 6 | DI container wire 3 services | ✅ SHIPPED |
| 7-9 | DB Step 1-3（建表 / migrate / verify）| ✅ SHIPPED |
| 10 | E2E 測試 | ⏭ **SKIPPED**（Phase 2 重設計，throwaway）|
| 11A/B | jedi-oscal cleanup + 主專案 refactor | ✅ SHIPPED |
| 12 | DROP 舊表 + 舊 M2M | ✅ SHIPPED |
| 13 | jedi-oscal bump + 推 Nexus + 主專案 pin 還原 | ⏭ **DEFERRED** to Task 12 Part 2 |
| 14 | Mini-handoff | ✅ SHIPPED (`2026-05-24-phase1-COMPLETE-SUMMARY.md`) |

### Phase 2（13 tasks）

| # | Task | Status | Commit |
|---|---|---|---|
| 1 | Pre-flight — parsed_result shape reference | ✅ SHIPPED | `6b577a55` |
| 2 | `ImportWarnings` collector module | ✅ SHIPPED | `aee0e991` |
| 3 | `ParsedBundleNormalizer` + warnings emission | ✅ SHIPPED | `ec9d3b20` |
| 4 | `SspImportConfirmService` + bundle_restore | ✅ SHIPPED | `f6069f83` + `901d3460` |
| 5A | `LeveragedWriteStrategy` v3 | ✅ SHIPPED | `dfdc6d98` |
| 5B | `ComponentWriteStrategy` v3 | ✅ SHIPPED | `d8c9a19d` |
| 5C | `InventoryItemWriteStrategy` v3（含 M2M）| ✅ SHIPPED | `d547f314` |
| 6 | Orchestrator + leveraged_reconciler v3（**Minimal scope**）| ✅ SHIPPED | `56f35d83` |
| 7 | Excel app service wire ConfirmService | ✅ SHIPPED（dispatch 落地 / parser gap 見 §6.2）| `f4cb9b10` |
| 8 | `CmmcSspAdapter.adapt_to_bundle` 輸出 v3 | ✅ SHIPPED | `e6bc9ede` |
| 9 | Docx app service wire ConfirmService | ✅ SHIPPED | `c681e3a8` |
| 11A | 刪 v2 strategies + dataclasses + helpers + reconcilers | ✅ SHIPPED | `9165b866` |
| 11B | Reviewer minor follow-ups（SourceTable enum / _strip_nulls DRY 等 7 點）| ✅ SHIPPED | `1e3abaee` |
| 12 Part 1 | Changelog + Final SUMMARY + design §11 update + conversation extract | ✅ SHIPPED（本文件）|  |
| 12 Part 2 | jedi-oscal 進版 + Nexus push + 主專案 pin 還原 | ⏸ **PENDING user 拍板**  |

**Note**：Plan 寫 Task 10 是 E2E pre-flight smoke，Phase 2 期間 user 拍板「重設計後寫」延到 Phase 3+ 一起做。Plan 也沒列 Task 11B（reviewer follow-up），實際是 Phase 2 review checkpoint 後自然產出的 minor cleanup。

---

## 2. 兩 repo commits 全清單

### jedi-oscal（18 commits，baseline `6f04da7`；Phase 1 期間 ship，Phase 2 全 0 commit）

| Commit | 摘要 |
|---|---|
| `ebadfe8` | refactor(oscal): remove deprecated SspSystemImplementationItem (Task 11A) |
| `ac1d860` | fix(oscal): harden InventoryItem M2M contract (PR-3 follow-up) |
| `2162af2` | feat(oscal): add InventoryItemDomainService (PR-3 part 6) |
| `646cc38` | feat(oscal): add InventoryItem repo + M2M write path (PR-3 part 5) |
| `1b22843` | feat(oscal): add InventoryItemMapper + tests (PR-3 part 4) |
| `c358d8e` | feat(oscal): add OscalInventoryImplementedComponent M2M ORM (PR-3 part 3) |
| `9d0db75` | feat(oscal): add OscalInventoryItem ORM (PR-3 part 2) |
| `1281121` | feat(oscal): add InventoryItemEntity + QueryEntity (PR-3 part 1) |
| `29b3bf0` | feat(oscal): add ComponentDomainService (PR-2 part 5) |
| `f498af1` | feat(oscal): add Component repo + impl (PR-2 part 4) |
| `697a460` | feat(oscal): add ComponentMapper + tests (PR-2 part 3) |
| `fdfd317` | feat(oscal): add OscalComponent ORM with partial index (PR-2 part 2) |
| `157d2bc` | feat(oscal): add ComponentEntity + QueryEntity + enums (PR-2 part 1) |
| `a748205` | feat(oscal): add LeveragedAuthorizationDomainService (PR-1 part 5) |
| `fed9970` | feat(oscal): add LeveragedAuthorization repo + impl (PR-1 part 4) |
| `773c5eb` | feat(oscal): add LeveragedAuthorizationMapper (PR-1 part 3) |
| `bf12dc9` | feat(oscal): add OscalLeveragedAuthorization ORM (PR-1 part 2) |
| `ab66af0` | feat(oscal): add LeveragedAuthorizationEntity + QueryEntity (PR-1 part 1) |

### 主專案（28 commits，baseline `d6fab20`）

**Phase 1（14 commits）**

| Commit | 摘要 |
|---|---|
| `dfefab08` | docs(ssp-oscal-alignment): Phase 1 COMPLETE mini-handoff |
| `af3b0952` | SQL migration step 4 — DROP 舊表 + 舊 M2M（Task 12）|
| `f9e6de75` | chore — update stale comment after Task 11A provider removal |
| `2776d151` | Task 11A — remove deprecated system_implementation_item DI providers |
| `94891eb3` | Task 11B-3 — remove 3 backward-compat shims + migrate 11 tests |
| `176c977b` | Task 11B-2 follow-up — migrate 3 context services props JSONB |
| `7d1d0a76` | Task 11B-2 — migrate app services + project layer |
| `5eaee305` | Task 11B-1 review — tighten LeveragedWriteStrategy except scope |
| `8a81c221` | Task 11B-1 — migrate write strategies from SspSystemImplementationItem |
| `af0ea339` | docs — Phase 1 Tasks 2-9 SHIPPED handoff |
| `1f944e2a` | docs — design.md v1.1 → v1.2 §11 reconciliation |
| `c5b43fbd` | Task 9 — SQL verification |
| `567efe73` | Task 8 — SQL migrate data |
| `a9712a12` | Task 7 — SQL create tables + RLS |
| `2e6849fb` | Task 6 — DI wire 3 services |
| `95e9efd2` | Task 5 — ParsedExcelEntityBundle restructure |

**Phase 2（14 commits）**

| Commit | 摘要 |
|---|---|
| `1e3abaee` | Task 11B — Phase 2.A/B reviewer minor follow-ups（7 點 cleanup）|
| `9165b866` | Task 11A — remove v2 strategies + dataclasses + helpers + reconcilers |
| `c681e3a8` | Task 9 — wire Docx app service through SspImportConfirmService |
| `e6bc9ede` | Task 8 — CmmcSspAdapter.adapt_to_bundle outputs v3 bundle |
| `f4cb9b10` | Task 7 — wire Excel app service through SspImportConfirmService |
| `56f35d83` | Task 6 — orchestrator + leveraged_reconciler v3（**Minimal scope**）|
| `d547f314` | Task 5C — InventoryItemWriteStrategy v3（M2M write）|
| `d8c9a19d` | Task 5B — ComponentWriteStrategy v3（consume ParsedComponent, resolve LA ref）|
| `dfdc6d98` | Task 5A — LeveragedWriteStrategy v3 |
| `901d3460` | Phase 2.A review — bundle_restore preserves reconciler fields + log orchestrator failures |
| `f6069f83` | Task 4 — SspImportConfirmService + bundle_restore |
| `6b577a55` | Task 1 — parsed_result shape reference |
| `ec9d3b20` | Task 3 — ParsedBundleNormalizer + warnings emission |
| `aee0e991` | Task 2 — ImportWarnings collector module |

---

## 3. Dev DB 最終狀態（cmmgr@192.168.50.188:25432/guidant_ai_dev — 密碼請查 `.env`）

```
oscal.ssp_leveraged_authorizations           rowsecurity=t   12 rows
oscal.ssp_components                          rowsecurity=t  341 rows  (164 hw + 165 system + 12 service)
oscal.ssp_inventory_items                     rowsecurity=t    0 rows  (Phase 3 Excel parser fix 後 Phase 2 confirm 流程才會寫入)
oscal.ssp_inventory_implemented_components    rowsecurity=t    0 rows  (M2M join)
```

舊表狀態（Phase 1 Task 12 DROP）：
- `oscal.ssp_system_implementation_items` → DROPPED
- `oscal.ssp_inventory_item_components` (OLD M2M) → DROPPED

FK linkage：12/12 service components 全綁回 leveraged_authorizations.uid（Phase 1 migration 期）。

**Note**：Phase 2 完工但 `ssp_inventory_items` 仍 0 rows 是因 Phase 2 期間沒新 import；新 import 經 Docx flow 應能寫入，Excel flow 待 Phase 3 §3.X parser 對齊。

---

## 4. 行為差異對使用者影響

### 4.1 Docx import — 完整 v3 path 通

`POST /api/1.0/ssp-docx-imports/parse` + `POST /api/1.0/ssp-docx-imports/<uid>/confirm`：
- Parse phase 同時 emit `ParsedSsp` overlay（Stage 1 docx-import-parity caller 仍依賴）+ v2-bundle `ParsedExcelEntityBundle`（merged into parsed_result with `schema_version="v2-bundle"`）。
- Confirm phase：controls / parties write 維持既有 path；LA → Component → InventoryItem 走新 `SspImportConfirmService.confirm()`（bundle_restore → normalize → orchestrator → 3 write strategies）。
- Bundle 失敗非 fatal — log warning + 422 fallback 不會 silent drop LA/Component data。

### 4.2 Excel import — 走 legacy path 拋 412（⚠️ Phase 3 §3.X 才能 close）

`POST /api/1.0/ssp-excel-imports/.../confirm`：
- App service dispatch logic 已落地（Task 7），但 parser 還沒輸出 `schema_version="v2-bundle"`。
- 結果：`parsed_result.get("schema_version", "v1-ssp") == "v1-ssp"` → 直接 raise `PreconditionFailedError(GRC_DOCX_PARSE_JOB_LEGACY_SHAPE, 412)`。
- 對使用者：Excel import flow 從「200 + 寫入舊表」變「412 提示重傳」。
- Phase 3 §3.X 改 Excel parser 後恢復 200 + 寫入新 OSCAL-correct 表。

### 4.3 移除的 dead code

Phase 2 Task 11A 刪：
- 5 個 src 檔（`device_write_strategy.py` / `information_system_write_strategy.py` / `base.py` AbstractSspComponentWriteStrategy / `device_reconciler.py` / `information_system_reconciler.py`）
- 4 個 test 檔（`test_a4_write_all_data_pipeline.py` / `test_a4_reconciliation_device.py` / `test_a4_reconciliation_information_system.py` / `test_a4_boundary_cases.py`）
- 3 個 v2 dataclass（`ParsedDevice` / `ParsedInformationSystem` / `ParsedLeveraged`）

**未來 caller 若 import 上述 symbol 會 ImportError** — Phase 3+ 引用者請 migrate 到 v3 dataclass + ConfirmService。

---

## 5. 規範文件齊全度

| 項目 | 路徑 | 狀態 |
|---|---|---|
| design.md v1.2 + §11 reconciliation（11 + 4 條 = **15 條** deviations）| `docs/features/FR-028-2605-ssp-oscal-alignment/design.md` | ✅ Phase 2 加 §11.12~§11.15 |
| implementation-plan-phase1.md + SHIPPED markers | `docs/features/FR-028-2605-ssp-oscal-alignment/implementation-plan-phase1.md` | ✅ |
| implementation-plan-phase2.md | `docs/features/FR-028-2605-ssp-oscal-alignment/implementation-plan-phase2.md` | ✅（SHIPPED markers 略）|
| Phase 1 mini-handoff | `docs/features/FR-028-2605-ssp-oscal-alignment/handoff/2026-05-24-phase1-COMPLETE-SUMMARY.md` | ✅ |
| Phase 1+2 Final SUMMARY（本文件）| `docs/features/FR-028-2605-ssp-oscal-alignment/handoff/2026-05-25-phase1-phase2-FINAL-SUMMARY.md` | ✅ |
| Changelog (batch Phase 1+2)| `docs/changelog/2026-05-25-feat-ssp-oscal-alignment-phase1-phase2.md` | ✅ |
| Conversation history JSONL extract | `docs/conversation-history/2026-05-24/ssp-oscal-alignment-phase2/` | ✅（7 個 .md）|
| Analysis 文件 | design.md §11 涵蓋（不另寫）| ✅ |

---

## 6. 已知 follow-ups

> ⚠️ **3 個 Phase 2 收尾留下的 leftover 抽到 §8（L1 / L2 / L3）獨立列**，下方是更早期的 follow-up 清單。

### 6.1 Production / API（Phase 3+ 處理）

1. **Excel parser v1→v2 gap**（⭐ 最高優先 — Phase 3 §3.X）：`domain/oscal/parser/excel/cmmc_excel_parser.py` 需輸出 `parsed_result["schema_version"] = "v2-bundle"` + `components` / `leveraged_authorizations` / `inventory_items` 三 list（mirror Docx Task 8 `adapt_to_bundle`）。改完 Excel import 從 412 變 200 + 寫入新表。
2. **`_parsed_ssp_to_dict_overlay`** 仍存在於 Docx app service（Stage 1 docx-import-parity 留下的 `ParsedSsp` overlay logic）— Phase 4 FE preview UI 重設計後可考慮整段刪掉，直接吃 v2-bundle。
3. **7 個 pre-existing pytest failures**（orthogonal，不在 Phase 2 root cause 範圍）— Task 11A commit message 已記錄「pytest tests/ 跟 c681e3a8 HEAD 同 7 個 failures，無新 failure」。下個 maintenance window 處理。
4. **Phase 4 FE preview UI 重設計**（design.md §4 / 5d 預估）：preview 需顯示 `ImportWarning` chip（normalizer.py 已 emit warnings）+ LA / Component / InventoryItem 三 sub-panel；template-edit 5-tab 第四 tab 必須改讀新表 — **這是 user-facing demo readiness 的關鍵 phase**（見 §9 demo gap）。
5. **OSCAL export endpoint**（design.md Phase 5 / 5d 預估）：round-trip verification 的最後一塊。

### 6.2 Phase 1 follow-ups（仍未處理，從 `2026-05-24-phase1-COMPLETE-SUMMARY.md` 延續）

6. **API contract `implementation_type` vs `component_type`**：`SspImportTemplateAppService._build_info_systems` dict key 改了，Phase 3 e2e 要驗 Excel template 下游沒人依賴舊 key。
7. **`project_device_route` 410-Gone 未實作**：`tests/test_c3_scope_migration.py::test_gone_response_uses_grc_error_code` 用 `@pytest.mark.skip`，獨立任務。
8. **Leveraged delete orphan service-Component**：用戶刪 LA 時 linked Component 變 orphan（`leveraged_authorization_uid` 指向已刪 LA.uid）— Phase 4 FE 重設計時處理。
9. **`AbstractSspComponentWriteStrategy.write()` `sys_impl_main_id` dead param** — Phase 2 Task 11A 刪 `base.py` 後此 follow-up 自動結案 ✅。

---

## 7. 部署 handover

### 7.1 Task 12 Part 2 — 套件進版 + 主專案 pin 還原（**user 拍板才執行**）

兩 repo 都還 local，未 push。Push 需 user 明確指示（per CLAUDE.md「push 永遠要 user 明確指示」）。

執行步驟（user 拍板後）：

```bash
# 1. jedi-oscal bump version
cd ~/Projects/Jedicogy/module/jedi-python-package/jedi-oscal
# 編輯 pyproject.toml: version = "0.0.18" → "0.1.0"
git add pyproject.toml
git commit -m "chore(jedi-oscal): bump 0.0.18 → 0.1.0 (OSCAL Component/LA/Inventory split)"
# push 到 Nexus（依套件 publish flow）

# 2. 主專案 pin 還原
cd ~/Projects/Billows/Audit-Manager/compliance-manager-be
# 編輯 pyproject.toml：
#   - line ~80 jedi-oscal pin: "^0.0.18" → "^0.1.0"
#   - line ~91 path dep 改回註解（dev-only）
poetry update jedi-oscal
# smoke：python main_app.py 8000 listening + DI 122 modules wired
git add pyproject.toml poetry.lock
git commit -m "chore(ssp-oscal-alignment): bump jedi-oscal 0.0.18 → 0.1.0 + restore pin"

# 3. 兩 repo push（user 明確指示後）
git push origin feature/ssp-oscal-alignment
cd ~/Projects/Jedicogy/module/jedi-python-package/jedi-oscal
git push origin feature/ssp-oscal-alignment
```

### 7.2 部署順序（兩 repo 同 deploy unit）

1. jedi-oscal 0.1.0 推 Nexus（先）
2. 主專案 deploy（pin 0.1.0 後）
3. DB migration 已在 Phase 1 跑完（dev DB 確認 + staging / prod 上線時補跑 `scripts/sql/2026-05-24-ssp-oscal-alignment-*.sql` 4 個檔）

### 7.3 FE 對齊（提醒）

Phase 4 FE preview UI 是 Phase 1+2 ship 後的後續 task — FE repo 路徑 `~/Projects/Billows/Audit-Manager/compliance-manager-fe`，建議切到 FE repo 開新 session 由 FE Claude 主導。Phase 1+2 本身**沒動 FE**，但 Excel import 412 行為差異會被 FE 既有 error toast 抓到。

---

## 7.4 收尾 Hotfix（2026-05-24 晚）

Phase 2 Task 12 Part 1 commit (`2bd8e7b3`) 之後，user 拉 docx import 跑端到端驗證，連續觸發兩個 latent bug：

### Hotfix 1 — Bug A：docx confirm 對 module_frame source 沒建 SSP shell（`ba0cdd7a`）

| 項目 | 內容 |
|---|---|
| 症狀 | docx import 成功，但 template-edit「外部利用服務」tab 仍空白 |
| Root cause | `_run_v2_bundle_confirm` 只 handle `source_type='project_ssp'`；module_frame branch ssp_id 留 None → `SspImportConfirmService` 拿不到 ssp_id 直接 skip LA/Component/Inventory writes |
| Fix | 抽出 `domain/oscal/service/ssp_shell_service.py`（DDD domain-service 層，無 infra import；含 `can_build` / `create_shell` / `resolve_existing_shell` / `ensure_shell`）；docx app service 新增 kwarg `ssp_shell_service`，module_frame branch 呼叫 `ensure_shell()` 取得 ssp_id 後才 delegate confirm_service |
| 範圍 | 新檔 `domain/oscal/service/ssp_shell_service.py`；修 `app/oscal/service/ssp_docx_import_app_service.py`（`__init__` + `_run_v2_bundle_confirm` + 新 helper `_derive_shell_description`）；Excel inline logic 不動（32 既有 tests 保留） |
| 教訓 | v3 wire-up 必須同時支援 superset / update / module_frame **三種** source_type；v2 → v3 過渡期 Excel/docx 流程 source_type 處理不對稱 → 留後門 latent bug |

### Hotfix 2 — RLS policy delimiter（`d12bd705`）

| 項目 | 內容 |
|---|---|
| 症狀 | Bug A 修完，docx confirm 第一次從 cm_app 真寫 4 張新表 → `DataError: invalid input syntax for type integer: '/1/102/'` |
| Root cause | Phase 1 §1.2 spec RLS policy 寫 split by `,`；實際 `session_scope` 設 `app.allowed_tenant_paths='/1/102/'`（slash-delimited path） |
| Why latent | Phase 1 Task 9 verify 用 cmmgr (superuser bypasses RLS) → false-positive ship；Bug A 沒 fix 時 confirm path 從沒實際 evaluate RLS |
| Fix | DROP + recreate 4 policies (`ssp_components_rls` / `ssp_leveraged_authorizations_rls` / `ssp_inventory_items_rls` / `ssp_inventory_implemented_components_rls`) 改用 `string_to_array(trim(both '/' from ...), '/')::integer[]` |
| Migration | `scripts/sql/2026-05-24-ssp-oscal-alignment-fix-rls-delimiter.sql` |
| 教訓 | 未來新增 RLS policy **一律 cm_app verify**（cmmgr superuser 等於沒測）；session 變數格式跨套件假設要在 spec 明寫 |

完整 root-cause 寫在 design.md §11.16（RLS）+ 待補 §11.17（Bug A — 本文件下方第 12 段補入）。

---

## 8. 已知 Leftover（必須在 Phase 3/4 收掉）

⚠️ **3 個未收尾項目，Phase 3/4 接手者開工前先掃過**：

### L1 — Task 12 Part 2：jedi-oscal 0.0.18 → 0.1.0 bump + Nexus push + 主專案 pin 還原

| 項目 | 內容 |
|---|---|
| 範圍 | jedi-oscal 套件 `pyproject.toml` bump、Nexus push、主專案 `pyproject.toml` path-dep 還原為 pin `^0.1.0`、`poetry update jedi-oscal`、兩 repo `git push` |
| 阻擋 | **user 拍板才執行** — 違反 CLAUDE.md「絕對禁止：自動執行套件發版」+「push 永遠要 user 明確指示」 |
| 時機 | 建議 Phase 3+4 全 ship 後一次性處理；中間 phase 還會改 jedi-oscal（特別 Phase 5 export）就再 bump 一次成本高 |
| 步驟 | 見 §7.1 |

### L2 — Bug B：docx import 5 parties 全 `decision=skip` → 0 parties 寫入

| 項目 | 內容 |
|---|---|
| 症狀 | user 用 docx import flow，diff stepper 顯示 5 parties，user 點確認後 0 parties 落到 DB → template-edit「責任單位 / 責任人員」tab 空白 |
| 推測 root cause | FE diff stepper 預設 `decision=skip` 而不是 `decision=accept`；user 沒手動切換就直接送 confirm → BE 全 skip 是正確行為 |
| 待釐清 | (a) FE 給的預設 decision 是哪個？(b) user 在 UI 上看到的有沒有預先 highlight？(c) BE response 顯示的 decision distribution 跟 user 看到的差異 |
| 行動 | Phase 4 FE 重設計時 BE/FE 共查；BE 端不主動改行為（accept-by-default 風險：user 沒看 diff 就誤寫資料）|

### L3 — Bug C：v2-bundle confirm 路徑沒套 `content_overrides`

| 項目 | 內容 |
|---|---|
| 症狀 | user 在 docx preview UI 改 component 類型 / LA 欄位 → submit 後 DB 仍是 parse 時原值 |
| Root cause | `ssp_docx_import_app_service._run_v2_bundle_confirm` 入口直接 `dict_to_bundle(parsed_result["bundle"])`；**沒套 `content_overrides`**。對比 Excel side `ssp_excel_import_app_service._apply_content_overrides` 有完整 metadata / system_characteristic / sheet rows / controls overrides handling |
| 範圍（fix outline）| 在 `_run_v2_bundle_confirm` 入口加 `_apply_content_overrides_to_bundle()` helper：拆 overrides 對 bundle.components / bundle.leveraged_authorizations / bundle.inventory_items 三 list 做 row-level update（mirror Excel `_apply_content_overrides` 的 sheet-row loop logic）|
| 注意 | Excel side override 是針對 parsed_result dict path（`row_overrides[sheet_key][row_idx]`）；v2-bundle 已是 dataclass list → 設 idx-based mapping 或 uid-based mapping，需先決定 |
| 時機 | Phase 4 開工時順手做（FE 改 preview 行為 → BE override path 一起對齊）|

---

## 9. ⚠️ User-facing demo readiness gap

**這段是 Phase 3/4 接手者必讀** — 解釋為何 Phase 1+2 完成 ≠ user 看得到 import 結果。

### 9.1 Phase 邊界對應 user-facing 問題

| Phase | 完成後 user 能做什麼 | 完成後 user **不能**做什麼 |
|---|---|---|
| Phase 1（DDD/DB foundation） | 後台資料模型正確；無 user-facing 行為 | 看不到 component / LA / inventory tab 內容 |
| Phase 2（Import pipeline 對接） | docx import 把 LA + Component + InventoryItem 寫進新表；Excel import 412 提示重傳 | **template-edit 5-tab 還是舊架構**，看不到新表內容 |
| Phase 3（Excel/Docx 樣板重設計） | Excel import 從 412 變 200 + 寫入新表 | template-edit FE 還是舊架構，仍看不到 |
| **Phase 4（FE preview UI 重設計）** | **template-edit 改讀新 ssp_components / ssp_leveraged_authorizations / ssp_inventory_items 表**，user 看到 import 結果 | OSCAL JSON export 還沒 |
| ~~Phase 5（OSCAL Export）~~ ⏸ deferred 2026-05-25 | ~~完整 round-trip：import → edit → export OSCAL JSON~~ | — |

### 9.2 為何 Phase 2 完工 user 還是「空白」（template-edit 截圖驗證）

驗證 case：MF `62c31d47-a90e-40e0-98ae-cb0c164a8acc`（SSP id=260）

| 後端 DB 真實狀態 | FE template-edit 顯示 |
|---|---|
| 1 LA + 4 Components 寫入新表 | 「外部利用服務 (1)」（**只看到 LA**） |
|  | 「設備 (0)」（讀舊 jedi_device 概念表）|
|  | 「資訊系統 (0)」（讀舊 jedi_information_system 概念表） |

**Root cause**：template-edit 5-tab 仍是 Phase 0 設計（OLD 三族 entity `device` / `information_system` / `leveraged`）；新表 `ssp_components` 沒有對應的 tab → 4 個 components 在 FE「不存在」。

驗證 query（密碼請查 `.env`）：

```sql
-- 連 cmmgr@192.168.50.188:25432/guidant_ai_dev
SET app.is_super_admin='t';
-- LA 由 SSP id 查
SELECT id, uid, title FROM oscal.ssp_leveraged_authorizations WHERE ssp_id=260;
-- Components 同上
SELECT id, uid, title, component_type FROM oscal.ssp_components WHERE ssp_id=260;
-- 對比 FE 截圖 → 確認 BE 有資料，差距在 FE 沒讀
```

### 9.3 Acceptance criteria 分三層

| 層 | 條件 | 由哪個 phase 收 |
|---|---|---|
| (a) BE 寫對 | DB 4 新表有正確資料 + RLS 通過 | Phase 1+2 ✅（已驗）|
| (b) UI 可看到 | template-edit 改讀新 `ssp_components` / `ssp_leveraged_authorizations` / `ssp_inventory_items`；新 tab「元件 + 授權 + 資產」 | **Phase 4**（最關鍵 demo gap） |
| (c) 完整 demo 流程 | Excel import 也通（不只 docx）+ OSCAL JSON export | Phase 3（Excel）+ Phase 5（export）|

**結論**：要做 user-facing demo readiness，**先做 Phase 4** 收 demo gap；Phase 3 解 Excel import path 但不阻擋 docx demo；Phase 5 是 round-trip 收尾。

---

## 10. 開發流程觀察（subagent-driven mode retrospective）

本 task arc 全程採 `superpowers:subagent-driven-development` mode：

| 觀察 | 說明 |
|---|---|
| Reviewer-after-implementer | Task 4 / 11B 兩次抓到 spec drift（bundle_restore 漏 reconciler field / SourceTable enum 該加）— review 投資值得 |
| Token budget | Phase 2 13 task 全 subagent，主 thread token 用量明顯低於同等 monolithic session |
| Wall clock | Task 5A/B/C 三 task 平行 dispatch（共用 v3 dataclass dep）— 比 sequential 快 |
| Trap | Task 6 plan 寫「filter components by type 再 dispatch reconciler」，第一次 dispatch implementer 照寫；review checkpoint 才提「reconciler 已 dead code，跳過更乾淨」→ 採 Minimal scope（§11.12）|

**Pattern baked into 後續 phase prompt**：DB-touching / 大規模 refactor task 開工前，controller 親查 schema + sample data + 看既有 caller 慣例（trust-but-verify pre-flight），再寫 implementer prompt。

---

## 11. 給 Phase 3 / Phase 4 接手 session 的 prompt（直接複製貼）

詳細版本（含 Phase 4 優先建議 + Bug B/C 開工前必處理）見 `docs/features/FR-028-2605-ssp-oscal-alignment/handoff/2026-05-25-phase3-4-handoff.md`。下方為精簡版：

```
你接手 SSP OSCAL Alignment Phase 3 — Excel/Docx 樣板重設計。Phase 1+2 完整 SHIPPED（28 主專案 commits + 18 jedi-oscal commits，全 local）。請按以下順序讀文件：

1. docs/features/FR-028-2605-ssp-oscal-alignment/handoff/2026-05-25-phase1-phase2-FINAL-SUMMARY.md（本文件 — 5 分鐘）
2. docs/features/FR-028-2605-ssp-oscal-alignment/design.md §11.12~§11.15（Phase 2 reconciliation）— 重點 §11.13 Excel parser gap
3. docs/features/FR-028-2605-ssp-oscal-alignment/design.md §3 Phase 3 段（Excel/Docx 樣板重設計 4d）
4. domain/oscal/import_pipeline/normalizer.py（理解 v2-bundle dict shape）
5. domain/oscal/adapter/cmmc_ssp_adapter.py:adapt_to_bundle()（Docx 端 v3 輸出 reference）

開工前 pre-flight：
1. 兩 repo branch:
   git branch --show-current  # 預期 feature/ssp-oscal-alignment
   git -C ~/Projects/Jedicogy/module/jedi-python-package/jedi-oscal branch --show-current
2. Dev DB 確認 Phase 2 final state（密碼請查 .env）：
   psql -h 192.168.50.188 -p 25432 -U cmmgr -d guidant_ai_dev -c "
   SET app.is_super_admin='t';
   SELECT
     (SELECT count(*) FROM oscal.ssp_leveraged_authorizations) AS la,
     (SELECT count(*) FROM oscal.ssp_components) AS comp,
     (SELECT count(*) FROM oscal.ssp_inventory_items) AS inv;"
   預期: la=12, comp=341, inv=0
3. Smoke：tail -50 log/app.log，預期無 Traceback；pytest tests/test_ssp_docx_import_app_service.py 應綠

Phase 3 §3.X 首要任務：改 Excel parser 輸出 v2-bundle dict shape，恢復 Excel import 從 412 變 200。
```

---

## 附錄 A — 路徑速查

| 用途 | 路徑 |
|---|---|
| Spec v1.2 + §11 reconciliation 15 條 | `docs/features/FR-028-2605-ssp-oscal-alignment/design.md` |
| Phase 1 plan | `docs/features/FR-028-2605-ssp-oscal-alignment/implementation-plan-phase1.md` |
| Phase 2 plan | `docs/features/FR-028-2605-ssp-oscal-alignment/implementation-plan-phase2.md` |
| Phase 1 mini-handoff | `docs/features/FR-028-2605-ssp-oscal-alignment/handoff/2026-05-24-phase1-COMPLETE-SUMMARY.md` |
| Phase 1+2 Final SUMMARY（本文件）| `docs/features/FR-028-2605-ssp-oscal-alignment/handoff/2026-05-25-phase1-phase2-FINAL-SUMMARY.md` |
| Phase 1+2 changelog | `docs/changelog/2026-05-25-feat-ssp-oscal-alignment-phase1-phase2.md` |
| Conversation history | `docs/conversation-history/2026-05-24/ssp-oscal-alignment-phase2/` |
| Import pipeline 新 module | `domain/oscal/import_pipeline/` |
| 新 entities（jedi-oscal）| `~/Projects/Jedicogy/module/jedi-python-package/jedi-oscal/jedi_oscal/domain/entity/base/oscal_{leveraged_authorization,component,inventory_item}_entity.py` |
| SQL migration 4 檔 | `scripts/sql/2026-05-24-ssp-oscal-alignment-*.sql` |
