# Handoff Prompt — A4 Session C → D（T0 + T1 + T2 ship → T3 + T4 + T5 開工）

> **使用方式**：把下方「交接 prompt 本體」整段貼到新 session 即可接手。
> **前置狀態**：A4 Session C BE shipped；working tree 乾淨（除 pre-existing pyproject.toml dev-path + zip）。

---

## 交接 prompt 本體（從此貼到新 session）

```
我要進 SSP 匯入匯出 Phase 2 / A4 Session D — T3 + T4 + T5。

前置狀態
========

Branch: feature/ssp-import-export-phase2（BE，42 commits 未 push）
- A4 Session A (design-A4.md) shipped：1de5f51（spec review approved）
- A4 Session B (implementation-plan-A4.md) shipped：57bcb2e（plan review approved）
- A4 Session C T0 pre-flight + T1 stage 0/dataclass/helpers shipped：57a9567
- A4 Session C T2 reconciler skeleton + orchestrator + DI shipped：72ef229
- jedi-oscal 仍 path-dep；pyproject.toml dev-path 改動仍未 commit
- A3 67 + A4 29 (T1) + 14 (T2) = 110 個 reconciliation/fixture test 全綠

Session C 結束 design §11.1 已紀錄 7 條 T0 偏差條目；以下偏差會直接影響 Session D：

⚠️ T0.4 偏差 — 影響 T3 AssessmentObjectiveReconciler ⭐
- design §5.3 EXACT stage 假設 CatalogControlAssessmentQueryEntity(catalog_control_id, objective_id)
- 實際 QueryEntity 無 objective_id 欄位（fields: id/uid/catalog_id/catalog_control_id/control_group_id/name/version/description）
- T3 改用 Option B：拉 catalog_control_id 範圍的全部 assessment list → Python 端 filter
  `getattr(ao, "statement_identifier", None) == parsed.objective_id`
- 細節見 design-A4.md §11.1.3

⚠️ T0.8 補驗 — 影響 T3 DeviceReconciler
- DeviceQueryEntity 有 name + ip 欄位 ✅；repo 繼承 BaseRepositoryImpl 走 AND filter ✅
- T3 開工前寫 1 個 integration smoke 驗 `DeviceQueryEntity(name=..., ip=...)` 實際 AND（避免 base behavior 被某些 override 打臉）

Session D 範圍
===============

T3 — 5 reconciler 完整演算法（implementation-plan-A4.md §Task 3）

5 reconciler 各填 5 hook 的演算法；TDD per stage：
- 3.1 DeviceReconciler ~12 test（4 user_selected + 4 exact + 4 normalized；無 fuzzy）
- 3.2 InformationSystemReconciler ~14 test（4 user_selected + 4 exact + 4 normalized + 2 system_owner）
- 3.3 LeveragedReconciler ~14 test（4 user_selected + 4 exact + 3 normalized + 3 fuzzy_name_prefix）
- 3.4 CatalogControlReconciler ~10 test（2 user_selected skip + 4 exact + 4 normalized；二階段）
- 3.5 AssessmentObjectiveReconciler ~10 test（受 T0.4 偏差影響 — 用 statement_identifier Python filter）

Commit：`feat(oscal): A4 T3 reconciler full algorithm`

T4 — A3 retroactive（implementation-plan-A4.md §Task 4）

A3 既有 PersonReconciler / OrganizationReconciler 加 stage 0 _try_user_selected_match
override；_dict_to_parsed_parties 加 matched_user / org_unit lookup 欄位傳遞。

- 4.1 PersonReconciler.override _try_user_selected_match — 用 parse_user_lookup_label
  → UserQueryEntity(login_name=...) 反查；不影響 A3 既有 7 test
- 4.2 OrganizationReconciler.override _try_user_selected_match — 用 OrgUnitQueryEntity(name=...)
  反查；不影響 A3 既有 8 test
- 4.3 _dict_to_parsed_parties 改：persons → matched_user_label / org_unit_label；
  orgs → matched_org_unit_label（parent_org 對應 lookup col）— 沿 design §6.5 寫法
- 4.4 補 ~6 test：test_a4_a3_retroactive.py 含 PersonReconciler / OrganizationReconciler
  各 2 stage 0 case + _dict_to_parsed_parties 加 label 2 case

T4 跟 T3 互不依賴 — 可平行做（T4 動 A3 既有 reconciler，T3 動 A4 新 reconciler）。

Commit：`feat(oscal): A4 T4 A3 retroactive USER_SELECTED stage`

T5 — A2 §15.3 整併（implementation-plan-A4.md §Task 5）

_confirm_superset_flow 內 include_controls 反查整併 — 依賴 T3 CatalogControlReconciler
完整實作。在 T3 ship 後做。

- 5.1 ssp_excel_import_app_service.py `_confirm_superset_flow` 內：parse_result 取 controls_with_aos
  list → 建 ParsedControl(control_id=...) 一次性 list → call catalog_control_reconciler.reconcile
  (parsed_for_resolve, fw_version.catalog_id) → 收集 matched_catalog_control_uid → 丟給
  ProfileService.add_profile(include_controls=...)
- 5.2 DI 加 catalog_control_reconciler 注入到 SspExcelImportAppService
- 5.3 ~4 integration test：test_a4_a2_integration.py 含 superset 反查 + edge case

Commit：`feat(oscal): A4 T5 A2 §15.3 superset include_controls 反查`

開工 SOP
========

第一步：必讀文件（順序）

1. docs/features/FR-011.2-2605-ssp-import-export-phase2/implementation-plan-A4.md
   ← §Task 3 / §Task 4 / §Task 5 段
2. docs/features/FR-011.2-2605-ssp-import-export-phase2/design-A4.md
   ← §5.3 5 reconciler 行為 / §5.4 InfoSystem system_owner 反查 / §5.5 AO reconcile_with_control_map /
     §6.4 A2 §15.3 整併 / §6.5 _dict_to_parsed_parties / §11.1 T0 偏差紀錄（特別 §11.1.3 T0.4）
3. domain/oscal/service/reconciliation/{device,information_system,leveraged,catalog_control,
   assessment_objective}_reconciler.py（T2 ship 的 skeleton）
4. domain/oscal/service/reconciliation/{person,organization}_reconciler.py（T4 要 override 的對象）
5. app/oscal/service/ssp_excel_import_app_service.py（T5 動 _confirm_superset_flow + _dict_to_parsed_parties）
6. domain/oscal/service/reconciliation/_normalizers.py（T1 ship 的 4 helper — T3 / T4 都會用）

讀完後給「我看完了，準備 T3 / T4 開工（互不依賴可平行）」確認。

第二步：T3 開工（每 reconciler TDD：寫 test → RED → 改 hook → GREEN → 下個 stage）

- 開工前對 jedi-device / jedi_information_system / oscal_party_domain_service / catalog_control_domain_service
  寫 1 個 integration smoke verify（DeviceQueryEntity AND filter / get_all signature / get_one signature）
- 用 plan §Task 3 樣板：每個 reconciler 內 5 hook 依序填，每填 1 stage 跑 1 次 pytest
- Commit T3：`feat(oscal): A4 T3 reconciler full algorithm`

第三步：T4 開工（A3 retroactive — 可跟 T3 平行）

- 用 plan §Task 4 樣板
- 改 person_reconciler.py / organization_reconciler.py 加 _try_user_selected_match override
- 改 ssp_excel_import_app_service.py `_dict_to_parsed_parties` 加 matched_user / org_unit / parent_org 傳遞
- 補 tests/test_a4_a3_retroactive.py
- Commit T4：`feat(oscal): A4 T4 A3 retroactive USER_SELECTED stage`

第四步：T5 開工（依賴 T3 — T3 ship 後做）

- 用 plan §Task 5 樣板
- 改 ssp_excel_import_app_service.py `_confirm_superset_flow` include_controls 反查
- DI 補 catalog_control_reconciler 注入 SspExcelImportAppService
- 補 tests/test_a4_a2_integration.py
- Commit T5：`feat(oscal): A4 T5 A2 §15.3 superset include_controls 反查`

第五步：Session D 收尾

依 plan §「換 Session 收尾規範」D → E：
- 跑 pytest tests/test_a3_*.py tests/test_a4_*.py 確認 0 regression
- git status --short 確認 working tree 乾淨（除 pre-existing pyproject.toml dev-path + zip）
- 產 handoff prompt → docs/features/FR-011.2-2605-ssp-import-export-phase2/handoff/2026-05-XX-a4-d-to-e.md
  含已 ship commits + T6/T7/T8 開工指引 + T0.1/T0.2/T0.5/T0.6/T0.7 偏差影響 Session E 提醒

鐵律（沿用 A0.1 + A1 + A2 + A3 + A4 全部）
==========================================

1. 顯式 git add <file>，禁 -am / -A — commit 前 git status --short 確認
2. jedi-oscal 維持 path-dep，不 bump 版本不推 Nexus（feature 整體完工才 bump）
3. pyproject.toml dev-path 改動不該 commit
4. BE 重啟必 lsof -ti:8000 | xargs kill -9
5. 改 BE service code 後必提醒 user 重啟 — BE 沒 hot reload
6. DDD 嚴格分層 — Route 不碰 DB，App Service @transaction，純函式 reconciler / WriteStrategy 不接 session
7. 不寫 docstring / 註解除非真有 non-obvious 的 why
   - A4 例外：SspEntityReconciliationOrchestrator facade docstring +
     AssessmentObjectiveReconciler.reconcile_with_control_map instance attr thread-safety note 屬「non-obvious why」
8. Test 用 mock 包 logger 避開 jedi DBLogHandler 撞 SessionLocal=None；@transaction 用 patch_session_scope
9. T0 verify 不符 design 假設 → 主動修 design-A4 §11.1 reconciliation（已寫 7 條）
10. 跨 repo 切換時提醒 user：cucumber 在 compliance-manager-test repo，commit / branch 分開
11. 重大決策 → docs/analysis/YYYY-MM-DD-<topic>.md
12. 重型 bug / 跨域問題 → docs/issues/pending/YYYY-MM-DD-<title>.md
13. Handoff 文件統一放 docs/features/<feature>/handoff/（CLAUDE.md 2026-05-20 新規）
14. 階段性 commit 不用問
15. Subagent dispatch prompt 必加「git add 顯式檔名，禁用 -am」
16. 套件異動需 user 拍板（jedi-* 加欄位 / 改 service 簽章前必先提）

Session D 預估規模
==================

- T3: 0.75d（5 reconciler 各 ~10-14 test = ~60 test）
- T4: 0.25d（PersonReconciler + OrganizationReconciler stage 0 + _dict_to_parsed_parties 改 + ~6 test）
- T5: 0.25d（_confirm_superset_flow 整併 + DI + ~4 integration test）

總計：~1.25d / 3 commit；T3 / T4 可平行做。

不在 Session D 範圍
====================

- SSP shell（T6 — Session E）
- 5 WriteStrategy（T7 — Session E）
- _write_all_data 8-step pipeline（T8 — Session E）
- Test 補齊 + Cucumber + 收尾（T9/T10/T11 — Session F）

工具預期
========

- 直接照 plan A4 樣板：每 stage TDD
- T3 5 個 reconciler 各自 commit 或合 1 個 commit 都行（plan 建議合 1 個 T3 commit）
- 不需 dispatch subagent — Session D 工作量在主 session 推得動

謝謝。
```

---

## 收口清單（A4 C → D 端）

本 handoff prompt commit 後，新 session 接手即可：

1. 讀 6 個必讀文件（plan-A4 §Task 3-5 / design-A4 §5/§6/§11 / 5 skeleton reconciler / 2 A3 reconciler / ssp_excel_import_app_service / _normalizers）
2. T3 5 reconciler 完整演算法（受 T0.4 偏差影響 — AO 改 statement_identifier Python filter）
3. T4 A3 retroactive（PersonReconciler / OrganizationReconciler stage 0 + _dict_to_parsed_parties label 傳遞）
4. T5 A2 §15.3 整併（_confirm_superset_flow include_controls 反查）
5. Session D → E 收尾（產下個 handoff，提醒 T0.1/T0.2/T0.5/T0.6/T0.7 影響 Session E）

## A4 完成度 reference（Session D 直接擴）

A4 Session D 直接擴的 A3 + A4 Session A/B/C 產物：

```
design-A4.md（含 §11.1 — 7 條 T0 偏差紀錄；plan / spec review 都 approved）
implementation-plan-A4.md（3466 行 / 11 task / 4 session）

domain/oscal/service/reconciliation/
├── base.py                                   # A4 T1: stage 0 dispatch + default no-op
├── match_method.py                           # A4 T1: USER_SELECTED
├── _normalizers.py                           # A4 T1: 4 helper (3 label parser + _normalize_control_id)
├── person_reconciler.py                      # A4 T4 加 stage 0 override (Session D)
├── organization_reconciler.py                # A4 T4 加 stage 0 override (Session D)
├── device_reconciler.py                      # A4 T2 skeleton (T3 填演算法 — Session D)
├── information_system_reconciler.py          # A4 T2 skeleton (T3 填演算法 + system_owner — Session D)
├── leveraged_reconciler.py                   # A4 T2 skeleton (T3 填演算法 + FUZZY_NAME_PREFIX — Session D)
├── catalog_control_reconciler.py             # A4 T2 skeleton (T3 二階段 — Session D)
├── assessment_objective_reconciler.py        # A4 T2 skeleton (T3 EXACT 受 T0.4 偏差影響 — Session D)
└── ssp_entity_orchestrator.py                # A4 T2 facade (完成)

domain/oscal/parser/ssp_intermediate.py       # A4 T1: 5 dataclass + Bundle + Context + ParsedParty 2 label

di_containers/oscal/oscal_containers.py       # A4 T2: device_container DependenciesContainer + 6 Factory
di_containers/containers.py                   # A4 T2: device_container 注入 oscal_container
```

## A4 Session C 規範遵守

- [x] 顯式 `git add <file>` 顯式檔名（T1 8 檔 + T2 14 檔，禁 -A）
- [x] Commit 含 `Co-Authored-By: Claude Opus 4.7 (1M context)` footer
- [x] jedi-oscal 沒動（path-dep 維持）
- [x] `pyproject.toml` dev-path 不 commit
- [x] DDD 規範貫徹（reconciler 純 domain，無 session / @transaction）
- [x] T0 pre-flight 8 項 verify 完成；不符項目補 design §11.1（7 條偏差條目）
- [x] handoff 文件統一放 `docs/features/<feature>/handoff/`
- [x] Session C 預估 ~1.5d 實際在 1 session 內完成
