# Handoff Prompt — A3 Brainstorm Kickoff（共用 matcher 抽取：parties / org-units）

> **使用方式**：把下方「交接 prompt 本體」整段貼到新 session 即可接手。
> **前置狀態**：A2 BE 完整 shipped（9 commits + 205 test 全綠）；working tree 乾淨；A3 是重型 phase 第一次開工，要走 superpowers:brainstorming SOP。

---

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

```
我要進 SSP 匯入匯出 Phase 2 / A3 phase brainstorm。

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

Branch: feature/ssp-import-export-phase2（BE，30+ commits 未 push）
- A0 / A0.1 / A1 / A2 都 BE shipped；A3 是 Phase 2 第 4 個 task arc
- 工具狀態：jedi-oscal 仍 path-dep；pyproject.toml dev-path 改動仍未 commit
- Test: 205 passed (A1 既有 106 + A2 新增 99)

A3 是重型 phase（requirement-understanding §6.1）→ 走完整 brainstorm SOP：
brainstorm 收斂 → design-A3.md → implementation-plan-A3.md → 開工

開工 SOP
========

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

1. docs/features/FR-011.2-2605-ssp-import-export-phase2/handoff/2026-05-19-a1-SUMMARY-t6-final.md
   ← A1 整段收口（207 行）— A2/A3 都建在 A1 樣板基礎上
2. docs/features/FR-011.2-2605-ssp-import-export-phase2/design-A2.md (v1.x, 含 §15.1-15.3)
   ← A2 phase design + reconciliation
   ← 特別看 §12 follow-up 第 2 條（A3 範圍 parties / org-units matcher 抽出）
   ← 特別看 §15.3 superset flow include_controls 待 A4 — 跟 A3 無直接關係但要記住
3. docs/features/FR-011.2-2605-ssp-import-export-phase2/requirement-understanding.md
   ← §6.2 Track A 階段表 A3 row（line 434）
   ← §6.4 A3 ship 條件（line 480）
   ← 風險表 line 541、547、568（A3 抽不乾淨會踩 A4 follow-up）
4. docs/features/FR-011.2-2605-ssp-import-export-phase2/README.md
   ← Phase 2 整體 tracker — A2 row 標 BE shipped；A3 row pending
5. docs/issues/pending/2026-05-19-person-role-cross-domain-inconsistency.md
   ← issue 修補 B / C 跟 A3 範圍有重疊（docx parser role normalize + DB 髒資料 audit）
6. domain/oscal/service/party_reconciliation_service.py（97 行）
   ← 抽出的對象 — 目前 docx 用、A2 confirm 也接但未明用

讀完後給「我看完了，建議下一步 X」的簡短確認。

第二步：Brainstorm 收斂（superpowers:brainstorming）

A3 重點 question 清單（brainstorm 時務必確認）：

1. 共用 matcher 的擺放層級
   - 選項 A：domain/oscal/service/（既有位置）— 純 domain logic，無 app 層依賴
   - 選項 B：app/oscal/service/matching/（新建）— app service 層，可依賴多個 domain service
   - 選項 C：抽到 jedi-oscal 套件（跨專案共用，但動 jedi 套件需 user 拍板）
   現有 PartyReconciliationService 在 domain 層 + 注入 user_domain_service + org_unit_domain_service。
   抽共用如何安排？

2. matched / unmatched / fuzzy 三狀態的 contract
   - 既有實作：email exact match (person) / name exact match (organization) — 二態（matched / unmatched）
   - A3 是否引入 fuzzy 狀態？fuzzy 場景：name normalize (大小寫 / 全形半形) / Levenshtein 距離 / email domain match
   - fuzzy match 結果 user 要明確確認還是自動接受？
   - 對 issue 修補 B（docx role normalize 字串 → ParticipantRole）是否一併納入 fuzzy matcher？

3. 既有 docx 路徑切換時的 regression 策略
   - 切換前後測試：docx parser path 行為「100% 不變」是 ship 條件（requirement §6.4）
   - 跨 repo cucumber regression 必跑 — 但 user 端 GitLab env 未配齊（A0.1 follow-up #7）
   - 過渡期是否雙路徑並存（feature flag），確認 regression 後再砍舊路徑？

4. fuzzy matching 演算法精細度
   - Email：exact only？還是 normalize (lowercase / trim / 移除 +alias)？
   - Person name：normalize？模糊？（中文姓名常見「王小明」vs「王 小明」空格不同）
   - Org name：normalize？「股份有限公司」vs「股份有限公司股份」尾綴差異？
   - 第一版接受多少模糊度？太鬆 → false positive 害 user 確認；太緊 → unmatched 太多

5. 跟 issue 修補 B 整併還是拆開
   - 修補 B：docx parser 加 role normalize map（OSCAL 字串 → ParticipantRole）
   - A3 範圍 matcher 抽出 — 跟 role normalize **不在同層**，但同樣是「字串歧義 → 系統實體」對映問題
   - 整併進 A3：matcher 統一處理 user / org / role 三類映射
   - 拆開：A3 只動 user / org，role 另開 issue resolution commit
   建議在 brainstorm 階段拍板。

6. A4 對 A3 的「擴展契約」
   - A4 加 devices / info_systems / leveraged / controls / AOs 5 種新 matcher
   - A3 抽出的共用 base 要長什麼樣才能讓 A4 直接擴？
   - Generics / Strategy pattern / 各 matcher 自己一個 class？

第三步：Pre-flight Verification（design 寫之前必做）

在 brainstorm 收斂後 / design.md 寫之前，verify 下列假設：

- [ ] PartyReconciliationService 唯一 caller 是 docx import flow（grep `party_reconciliation_service` 確認）
- [ ] A2 SspExcelImportAppService.__init__ 已 inject reconciliation 但 `_confirm_*` flow 沒實際使用（confirm 直接走 ModuleFrameWriteStrategy.write_parties，沒先 reconcile）— A3 是否同時補上 A2 的 reconcile 串接
- [ ] jedi-auth UserQueryEntity / OrgUnitQueryEntity 既有欄位（reconciliation 既有靠 RLS 自動 tenant 過濾，這部分要不要動）
- [ ] cucumber 既有 docx import scenarios 有沒有 cover matched / unmatched 標記（regression test 基準）
- [ ] cucumber compliance-manager-test repo 結構（A3 ship 要新測試覆蓋）

每項用具體 grep / read 命令在 brainstorm log 內列。

第四步：產出 design-A3.md + implementation-plan-A3.md

brainstorm 拍板後：
- design-A3.md 寫到 docs/features/FR-011.2-2605-ssp-import-export-phase2/design-A3.md
- implementation-plan-A3.md 寫到 docs/features/FR-011.2-2605-ssp-import-export-phase2/implementation-plan-A3.md
- 路徑 override（CLAUDE.md 規範）：brainstorming spec / writing-plans plan 都放這資料夾，不要走 docs/superpowers/specs/

問我 brainstorm 各題答案後才開工，不要直接動 code。

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

1. 顯式 git add <file>，禁 -am / -A — commit 前 git status --short 確認
2. jedi-oscal 維持 path-dep，不 bump 版本不推 Nexus（Phase 2 整體完工才 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，純函式 helper / matcher 不接 DB
7. 不寫 docstring / 註解除非真有 non-obvious 的 why
8. Test 用 mock 包 logger 避開 jedi DBLogHandler 撞 SessionLocal=None；@transaction 用 patch_session_scope 接 contextlib.contextmanager
9. T0/Pre-flight verify 結果不符 design 假設時主動修 design.md (§15 reconciliation)
10. 跨 repo 切換時提醒 user：cucumber 在 compliance-manager-test repo，commit / branch 分開
11. 改 docx parser 既有行為 → cucumber regression 必跑 — 是 ship 必要條件
12. 重大決策 → docs/analysis/YYYY-MM-DD-<topic>.md（trade-off 取捨理由）
13. 重型 bug / 跨域問題 → docs/issues/pending/YYYY-MM-DD-<title>.md（不擠在 changelog）
14. Handoff 文件統一放 docs/features/<feature>/handoff/（CLAUDE.md 2026-05-20 新規）

A1 + A2 既有 contracts（A3 必看）
================================

PartyReconciliationService 現有 contract
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

位置: domain/oscal/service/party_reconciliation_service.py (97 行)
DI: di_containers/oscal/oscal_containers.py:482 (Factory)
唯一 method:
  reconcile(parties: List[ParsedParty], tenant_id: Optional[int]) -> List[ParsedParty]
  - 對 person：email lowercased+trim → UserQueryEntity 找 → matched_user_id
  - 對 organization：name trimmed → OrgUnitQueryEntity 找 → matched_org_unit_id
  - in-place mutate + return same list
  - tenant 隔離靠 RLS（不在 service 層加 filter）

Caller:
  - docx import flow: SspDocxImportAppService.upload_and_parse line 258-264
    (parse 階段就跑 reconcile，結果存 parsed_result.parties)
  - A2 Excel import flow: 已 inject 但 _write_all_data 沒呼叫 reconcile —
    parties 直接走 ModuleFrameWriteStrategy.write_parties 寫入（無 matched 標記）
    這是 A3 要補的串接點之一

ParsedParty 結構
~~~~~~~~~~~~~~~

domain/oscal/parser/ssp_intermediate.py line 50:
  @dataclass
  class ParsedParty:
      name: str
      party_type: Literal["person", "organization"]
      role: Optional[str]
      email_address: Optional[str]
      ...
      matched_user_id: Optional[int]      # ← reconciliation 填
      matched_org_unit_id: Optional[int]  # ← reconciliation 填
      target_party_uid: Optional[str]     # diff service 用

A3 抽共用後仍保留此 dataclass（contract 對外不動）— 變的是內部演算法
跟可能新增的 fuzzy 狀態欄位（如 match_confidence / match_method）。

OSCAL 表寫入點（A3 結果最終落地處）
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

ModuleFrameWriteStrategy.write_parties (domain/oscal/strategy/module_frame_write_strategy.py:265)
  - 接 List[ParsedParty]
  - 寫 oscal_parties (按 matched_user_id / matched_org_unit_id 填欄位)
  - 寫 oscal_responsible_parties (link to module_frame context)

SspWriteStrategy 同上 pattern but context_type='ssp'

issue 修補 A / B / C 對齊
~~~~~~~~~~~~~~~~~~~~~~

修補 A（A2 已做）：Excel parser 03 sheet role enum validation
修補 B（A3 可整併）：既有 docx parser 加 role normalize map
修補 C（A3 後）：dev DB oscal_responsible_parties.role_id 髒資料 audit + 清理
修補 D（後遠期）：OSCAL party ↔ project_participant 雙寫設計（不在 A3 範圍）

已知限制 / risk
================

- BE 完整 boot 撞 jedi-issue GitLab env 問題（A0.1 follow-up #7，非 A3 引入）
- cucumber regression 需 user 端配齊 GitLab env 後才能完整跑
- 改 docx parser path 行為若有偏差 → 影響 SSP docx 匯入 existing customer flow
- pre-existing test fail: test_write_parties_refreshes_existing_party_in_place（非 A3 引入）

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

- 用既有 superpowers:brainstorming skill 走完整 6 question 收斂
- 用既有 superpowers:writing-plans skill 寫 implementation-plan-A3
- Subagent 平行查（Explore agent）— PartyReconciliationService caller 盤點 / cucumber existing matched 標記 scenarios / jedi-auth UserQueryEntity 既有支援

謝謝。
```

---

## 收口清單

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

1. 讀 6 個必讀文件
2. Brainstorm 6 個 question 拍板
3. Pre-flight verify 5 項假設
4. 產 design-A3.md + implementation-plan-A3.md
5. 等 user GO 才開 T0

## A3 phase 預估規模

- Brainstorm: 0.5d（含 6 question 收斂 + verify）
- design-A3.md + plan-A3.md 產出: 0.5d
- T0 verify: 0.25d
- T1 抽 PartyReconciliationService 共用層: 0.5d
- T2 docx path 切換 + regression: 0.5d
- T3 A2 path 串接 matcher: 0.25d
- T4 fuzzy matching 演算法（若 brainstorm 拍板要做）: 0.5d
- T5 unit test + cucumber regression: 0.5d
- T6 changelog + tracker: 0.25d

**總計**：~3.25 working day（不含 cucumber 跑 BE smoke 需 user 配齊 env）

## 跨 repo 影響

| Repo | 預期工作 |
|------|---------|
| BE（主）| matcher 抽共用層 + docx path 切換 + A2 path 串接 + unit test |
| FE | A3 phase **不動 FE**（matched 標記已有 schema 接，預覽 UI 在 A5 補）|
| jedi-* | **不動**（reconciliation 維持在主專案）— 除非 brainstorm 選項 C 才動 jedi-oscal |
| test | cucumber regression：docx existing matched scenarios + 新加 fuzzy match scenarios |
| changelog | `docs/changelog/YYYY-MM-DD-feat-party-matcher-shared.md` + 可能 `tweak-docx-role-normalize.md` |

## 既有 A1/A2 commit 鏈速查

詳見 `docs/features/FR-011.2-2605-ssp-import-export-phase2/README.md` tracker。

A3 起手前不需要 push BE branch（30+ commits 累積中，等 Phase 2 主線完工或 user 拍板才 push）。
