使用方式:把下方「交接 prompt 本體」整段貼到新 session 即可接手。 前置狀態:A4 Session C BE shipped;working tree 乾淨(除 pre-existing pyproject.toml dev-path + zip)。
我要進 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 推得動
謝謝。
本 handoff prompt commit 後,新 session 接手即可:
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