# FR-038 Wave 2 — 主專案 BE 遷移 Implementation Plan

> **For agentic workers:** 用 superpowers:subagent-driven-development 逐 task 執行。Steps 用 `- [ ]`。
> 上游：Wave 1（`jedi-oscal-v2` 套件）已完成，見 [handoff](handoff/2026-06-14-wave1-SUMMARY-and-wave2-handoff.md)。契約：[design.md](design.md) + [oscal-v2-deltas.sql](oscal-v2-deltas.sql) + [api-contract.md](api-contract.md)。

**Goal:** 把主專案 compliance-manager-be 從舊 `jedi-oscal` 0.0.22 遷移到 `jedi-oscal-v2`，落地新業務流程（專案成立 clone 三件組、稽核輪次 `project_audit_rounds`、AP 延後到輪次、AR AO 全量矩陣、整改三層），讓 dev BE 從「新 schema + 舊 code 壞掉」恢復成可運作的新架構。

**Architecture:** ~110 檔（**live grep 2026-06-14 = 109 source 檔**，含 test 約 115）分 Type A（改 import+呼叫）/ B（改簽名+業邏輯）/ C（整段重寫）。DI 容器一次切換到 v2、同批改所有 consumer。新增 `project_audit_rounds` 為輪次 first-class。重建 DROP CASCADE 掉的 FK/view。

**Tech Stack:** Flask + SQLAlchemy 2.0 + PostgreSQL（DDD），`jedi-oscal-v2`（path-dep dev），pytest（`test/`）。

**Scope:** 只 BE（主專案）。FE 是 Wave 3。估 62–81h。

---

## 0. Pre-flight（每個 task agent 開工必做）
- [ ] 讀 [handoff §2](handoff/2026-06-14-wave1-SUMMARY-and-wave2-handoff.md)（遷移盤點 + DROP CASCADE 待重建 + Type C 重寫點）
- [ ] 讀 `jedi-oscal-v2` 對外 service 簽章（handoff §1 列表）+ 套件 `__init__.py`
- [ ] 確認主專案 `pyproject.toml` 已有 `jedi-oscal-v2` path-dep（dev-only，未 commit）
- [ ] **驗 dev BE 起得來**：遷移過程中常態壞，每個 phase 末跑 `python main_socketio.py` smoke + 既有 `pytest test/` baseline diff（記憶 `feedback_baseline_worktree_regression_diff`）

---

## 1. 遷移順序（依賴鏈，大部分序列）

```
Phase 2.0 前置（序列瓶頸）
  ├─ 2.0a DI 容器切換 v2 + Type A 批次改 import（一起做，否則 DI 一切就全壞）
  ├─ 2.0b 重建 / 廢棄 compliance FK（fk_ape）
  └─ 2.0c 重寫 vw_user_job_queue（對新 ap_tasks）
       ▼
B1 框架 + 資源庫 API 對齊新套件 ── 相對獨立，可與 B2 並進
       ▼
B2 專案成立流程重寫（clone 三件組，AP/AR 延後）   ← Type C
       ▼
B3 SSP 維護 + 啟動稽核 snapshot + project_audit_rounds 狀態機   ← Type C
       ▼
B4 AP 後端（草稿生成 + CRUD + subjects）
       ▼
B5 AR（AO 全量矩陣 + 風險總結）+ POA&M（整改三層 + 結案/覆核）   ← Type C
       ▼
Phase 2.Z 全 e2e（精誠機械 CMMC 劇本）+ baseline 零回歸
```

**能平行的**：Type A 批次（純改 import）可多 agent 分檔平行；B1 與 B2 可並進。**必序列的**：2.0a（DI 一切）、B2→B3→B5 的業務鏈、Type C 重寫。

---

## Phase 2.0 — 前置（序列，必先完成）

### Task 2.0a: DI 切換 v2 + Type A 批次改 import

> ⚠️ **本段「~40 檔 import-rename」框架已被 2026-06-14 驗證推翻** —— v2 是結構性重寫（domain-service 層收掉、AO/AP-task/AR-data 表結構全變），且新舊套件 ORM model 撞同一 MetaData **無法共存**（全切被強制、無 booting 中間態）。2A 正解是 **gut-and-disable**（v2 primitives 接真、B1~B5 業務面乾淨 disable、My Jobs 重寫），不是 import-rename，也不是 stub-everything。**完整修正版執行計畫見 [`handoff/2026-06-14-2A-corrected-gut-and-disable-handoff.md`](handoff/2026-06-14-2A-corrected-gut-and-disable-handoff.md)（含 boot 必經面清單 / v2 wiring map / disable 手法 / My Jobs 重寫 / boot 驗證指令）。**

**Files:** `di_containers/oscal/oscal_containers.py`（**實際 1074 行，verified —— 是 Phase 2.0 最大單一工作量，別照舊估的 150 行排程**）+ ~40 Type A 檔（infra model/mapper/repo、domain entity import）
- [ ] 重寫 `OscalContainer`：31+ provider 從 `jedi_oscal.*` 改 `jedi_oscal_v2.*`（service/repo），對照新套件對外 service 清單。
- [ ] 批次改 Type A 檔的 import（`from jedi_oscal` → `from jedi_oscal_v2`），調整改名/搬移的 symbol。**顯式 git add 分批 commit，禁 `-am`**（記憶 `feedback_subagent_explicit_git_add`）。
- [ ] 注意：舊套件有些 model 在新套件改名/結構變（如舊 `assessment_result_datas` 沒了、AO 從 `catalog_control_assessments` 改 `catalog_control_parts`）→ 這些 consumer 落 Type B/C，本 task 只搬「直接對應」的。
- [ ] **驗**：`python -c` import smoke 全綠 + DI container wire 不炸。
- [ ] commit。

### Task 2.0b: compliance FK 重建 / 廢棄判定  ⛔ **USER-DECISION GATE，不要自己決定**
**Files:** 新 migration `scripts/sql/2026-XX-XX-fr038-wave2-rebuild-fk.sql`
- [ ] **這是架構決策（keep+rebuild vs DROP），停下問 user，不要 agent 自己拍**：`compliance.assessment_plan_extensions` 在新 `project_audit_rounds` 模型下是否還需要？
  - **我的建議（給 user 參考）**：新架構輪次/AP 關聯已搬到 `project_audit_rounds`，`assessment_plan_extensions`（module_frame_id/owner_id 等 AP 延伸）**很可能被 project_audit_rounds + project_extensions 取代 → 傾向 DROP**；但需 grep 確認其 live consumer（`grep -rl assessment_plan_extension app/ infra/ domain/`）零引用才能 DROP。
- [ ] user 拍板後才動：保留 → 查 orphan（`assessment_plan_id NOT IN (SELECT id FROM oscal.assessment_plans)`）清理 → `ALTER TABLE ... ADD CONSTRAINT fk_ape_assessment_plan ...`；廢棄 → 記錄決策 + DROP。
- [ ] migration 走 cmmgr + `--single-transaction -v ON_ERROR_STOP=1` + INSERT schema_migrations（記憶 SQL 鐵則）。

### Task 2.0c: 重寫 vw_user_job_queue
**Files:** `scripts/sql/view/vw_user_job_queue.sql`（重寫）+ `infra/participant/model/vw_user_job_queue.py`（ORM mirror 跟著改）+ consumer `infra/participant/repository/task_assignee_repo_impl.py`
- [ ] **不能 replay**：原 view join 的 4 張舊 AP 表（assessment_plan_task_workflow_execution_mapping / assessment_plan_controls / assessment_plan_groups / assessment_plan_tasks）新 schema 都沒了。
- [ ] 對齊 Q1：任務執行 job 綁「專案 SSP 控制項」、非 AP task。重寫 view 對新來源（SSP 控制項 + workflow_execution + task_assignees + job_executions）。
- [ ] ORM mirror + repo consumer 跟著新 column set 改。驗 My Jobs 頁資料正確。

---

## Phase B1 — 框架 + 資源庫 API 對齊（可與 B2 並進）
**Files:** `api/module_frame/`、`app/module_frame/service/*`、相關 repo
- [ ] 框架 CRUD/匯入：改呼叫 `jedi_oscal_v2` FrameworkService / CatalogService（CMMC parser）。
- [ ] 資源庫（module_frame）：改成 catalog+profile+ssp 三件組語意；建立資源庫時 `resolve_profile` → catalog 副本（邊界①）。匯入 SSP docx/excel 落地新 schema（注意：套件 docx/excel **匯入** 是 follow-up，本期若需要要先補套件或暫沿用舊路徑轉接）。
- [ ] 對齊 [api-contract.md](api-contract.md) 框架/資源庫段。

---

## Phase B2 — 專案成立流程重寫（Type C）
**Files:** `app/project/service/oscal_project_service.py`（核心重寫）+ `api/project/routes/project_route.py`
- [ ] `start_oscal_project()` 拆成 **`start_project`**：clone 最新發布資源庫三件組（`clone_resource_library` 邊界②）+ 建 project 主檔 + participant + **為 SSP 控制項建 workflow job（Q1，專案成立就建，非 AP task）**。**AP/AR 不在此建**。
- [ ] 移除舊「啟動時建 AP/AR + 為 AP task 建 workflow」邏輯。
- [ ] 改 `project_assessment_plan_mapping` 等關聯（AP→ `project_audit_rounds`）。
- [ ] 對齊 api-contract project-start 段。全 e2e（建專案→看到三件組 clone）。

---

## Phase B3 — SSP 維護 + 啟動稽核 snapshot + 輪次狀態機（Type C）
**Files:** `app/oscal/service/*`（SSP）、新 `app/grc/service/audit_round_service.py`、`api/grc/routes/`
- [ ] SSP 維護路由對齊新 `jedi_oscal_v2` SspService（system-characteristics/parties/components/inventory/implemented-requirements/SoA props）。
- [ ] **新 `project_audit_rounds` 狀態機**（7 態，見 oscal-v2-deltas.sql）：建輪次 / `launch-audit`（snapshot living SSP → `snapshot_ssp` 邊界③ → 填 round.ssp_id + 建/沿用 engagement 的 AP+AR）/ `launch-reverify`（close-out 開新 round，parent_round_id）。狀態轉換驗前置條件 + 角色權限（manager/auditor）+ error code（GRC_ROUND_*）。
- [ ] 對齊 api-contract audit-rounds 段。

---

## Phase B4 — AP 後端
**Files:** `app/grc/service/*`、`api/grc/routes/assessment_plan_route.py`
- [ ] AP 草稿生成（`generate_draft` from SSP 快照）+ reviewed-controls / subjects(抽查名單) / tasks CRUD，wire 到 `jedi_oscal_v2` AssessmentPlanService。
- [ ] 權限：auditor 寫 AP。對齊 api-contract AP 段。

---

## Phase B5 — AR（AO 全量矩陣 + 風險總結）+ POA&M + 結案/覆核（Type C）
**Files:** `app/grc/service/audit_service.py`、`infra/grc/repository/grc_audit_repo_impl.py`（重寫）、`app/grc/service/poam_service.py`、`api/grc/routes/{audit_route,poam_route}.py`
- [ ] AR 判定從「逐控制項 verdict」改 **AO 全量矩陣**（`init_finding_matrix` / `upsert_finding` / `list_findings` w/ stats），重寫 grc_audit_repo_impl 的 8+ 查詢。
- [ ] **風險總結**（新畫面後端）：稽核員手動建 risk + `link_findings` 多對多 + 等級在 risk 層（AssessmentRiskService）。
- [ ] POA&M：`generate_from_findings`（**gate 在 AR 定版後**，避免重複生）+ 整改三層（remediation→milestone，per-milestone assignee）+ 結案（全 POA&M closed）+ 覆核（launch-reverify）。
- [ ] error code（GRC_AR_* / GRC_RISK_* / GRC_ROUND_*）。對齊 api-contract AR/POA&M 段。

---

## Phase 2.Z — 整合驗證（序列收尾）
- [ ] 全 e2e 走一次完整生命週期（精誠機械 CMMC L2：建專案→編 SSP→啟動稽核 snapshot→AP→AR AO 判定→風險→POA&M→覆核→結案）。
- [ ] baseline 零回歸：跟遷移前 commit 的 `pytest test/` diff（記憶 `feedback_baseline_worktree_regression_diff`）。
- [ ] BE 起得來 + 主要 route smoke。
- [ ] （收尾：等 user 明示才 changelog/SUMMARY/發版套件）。

---

## 2. 風險與注意
- **DI 一切性**：2.0a 沒一次切乾淨會讓整個 BE import 炸 —— Type A 批次要跟 DI 同 PR 完成才能起 BE。
- **舊表沒了**：consumer 引用舊 `assessment_result_datas` / `catalog_control_assessments` / 舊 AP 子表的，要改對新結構（Type B/C），不是改 import 就好。
- **跨 schema FK 字串帶 schema 前綴**（記憶 `feedback_cross_schema_fk_must_qualify`）。
- **套件 docx/excel 匯入是 follow-up**：B1 若需要 SSP 匯入，要嘛先補套件、要嘛暫接舊路徑——開工前確認。
- **正式環境（D7）**：dev 用 drop&rebuild，stg/poc/prod 遷移策略未定，上正式前必須有可移植 migration（不能 drop schema）。
- 每個 Type C 完成各自全 e2e，不要堆到最後。
