稽核輪次階段推進的「返回上一階段」功能已在 BE + FE 全鏈完工並在 DEV 手測/冒煙通過;STG migration 已套(2026-07-19 指揮官執行,兩表+GRANT+schema_migrations 對帳綠;POC 未套、累計缺 4 支),E2E 場景四件組派工中(test-case 文件階段),design §6 六個驗收情境目前只做過 API 面/單元測試層級的對應驗證,尚未做完整 live 端到端走查。
| Commit | Repo | 內容 |
|---|---|---|
c3b3126e |
BE | docs(FR-050): implementation-plan 落地 — 13 task 全鏈規劃文件(migration/domain/rollback handlers×3/StageRollbackService/route/DI/repo)+ 四個 plan-time 裁定 + §4.4 superseded 裁決定案選 B |
9ee32a27 |
BE | feat(FR-050): 稽核輪次階段回退 BE 全鏈 — StageRollbackService + 三邊界 rollback handler + 階段歷程時間軸;新表 round_stage_transitions + round_rollback_supersessions;migration 已套 DEV;pytest 新增 31 全綠 |
9a1216ff |
BE | fix(FR-050): rollback_to_audit_planning 的 from_stage 誤寫 round.status 值 — "auditing" 改 "audit"(stage_objects.code 值域),DEV 資料校正 1 筆 + 測試補值域斷言鎖回歸 |
141cfcd1 |
FE | feat(FR-050): 稽核輪次階段回退 FE — FlowPhaseBanner 回退入口 + 階段歷程時間軸元件 + i18n + 錯誤碼對照 |
| # | 裁定 | 結論 |
|---|---|---|
| D1 | round_stage_transitions 是否加 tenant_id/org_unit_id/RLS |
不加 — 母表 project_audit_rounds 本身無 tenant_id/org_unit_id/RLS(軟隔離由上層 projects 把關),本表沿用同一家族慣例 |
| D2 | rollback handler 機制 | 複用同一個 StageRegistry singleton,加 register_rollback_handler/get_rollback_handler 兩方法 + _rollback_handlers dict,不另開新 registry class |
| D3 | 三個回退邊界 v1 開放幾條 | 三條全開(audit_planning→planning/auditing→audit_planning/remediation→auditing),對應 user 已拍板決策 A |
| D4 | round_stage_transitions 是否含 advance 方向 |
含 — advance 路徑補一行落表呼叫(非破壞性 delta,未注入時 no-op) |
design §4.4 列出兩個選項讓 user 裁決是否動 jedi-oscal-v2 套件:
jedi-oscal-v2 PublishStatus 加 SUPERSEDED 值——影響全部窮舉比對讀取點,跨套件異動需走發版流程。compliance.round_rollback_supersessions,不動 jedi-oscal-v2 任何檔。SSP/AP/POA&M 三種 entity 統一走本表機制;讀取封裝在 RoundRollbackSupersessionDomainService。理由:superseded 是 FR-050 回退流程的業務概念(天然帶 round_id + reason 脈絡),非 OSCAL 文件生命週期通用狀態,塞進套件 PublishStatus 屬 caller 業務知識下沉,違反套件異動分界原則;選項 A 的 grep 面(3 entity × 全部窮舉比對讀取點)成本不小。
| # | 衝突 | 裁決 |
|---|---|---|
| 1 | revert_job 呼叫既有「規劃期才可退回」凍結 gate,與 FR-050 回退邊界本身即發生在 status != planning 時直接衝突(plan §6/§8.3 未預見) |
BE 層 WorkflowExecutionService.revert_job 加 bypass_round_frozen_gate 參數(app/flow_engine/service/workflow_execution_service.py:820),僅 StageRollbackService 呼叫時傳 True;既有兩個呼叫點零行為變更(維持 False),test_workflow_execution_service_revert_job_bypass_gate.py 鎖回歸(bypass=False 仍擋) |
| 2 | error code 序號接續 | plan §5 草稿序號(GRC_412029/GRC_400077/GRC_412030/GRC_400078)在實作時因期間有其他 PR 併入、序號已被佔用,改採實作當下最新序號接續:GRC_412046/GRC_400096/GRC_412047/GRC_400097(見 common/code/grc_error_code.py:338-341) |
9a1216ff)rollback_to_audit_planning(auditing → audit_planning 邊界)落 round_stage_transitions 時,from_stage 誤寫成 round.status 值 "auditing",但欄位 schema COMMENT 規定一律存 stage_objects.code(正確值應為 "audit")——三個 rollback 方法中僅此一處混入錯值,FE 驗收時在 DEV DB 實查抓到(UI 時間軸顯示不一致)。
修正:
app/grc/service/audit_round_app_service.py 該行 from_stage 改 "audit"UPDATE 1 筆既有錯誤紀錄STAGE_OBJECT_CODES frozenset 值域斷言,鎖三個 rollback 方法的 from_stage/to_stage 一律落在合法 stage_objects.code 集合內——回歸來源是既有測試斷言與 bug 錯得一致(同寫 auditing),此次一併修正測試斷言test_stage_rollback_service.py(9)+ test_oscal_stage_rollback_handlers.py(7)+ test_workflow_execution_service_revert_job_bypass_gate.py(2)+ test_api_stage_rollback_route_smoke.py(4)+ test_audit_round_app_service.py(9,含新增值域斷言)= 31 passedtest_api_stage_rollback_route_smoke.py 涵蓋 3 個手測情境的 API 面對應(route-level smoke,非起 DB 真整合):
GET transitions envelope 結構schema_migrations 對帳綠)手測(DEV round 969ad600),commit message 記錄 6 項全過:
closed 輪次無 banner(整個不顯示)planning 階段無回退按鈕(鏈頭無上一步)transitionsStale 旗標機制:陣列非空後不再永不重抓、advance 後也會刷新未做。無 test repo 場景派工紀錄。
| 項目 | 現況 | 備註 |
|---|---|---|
| STG migration | ✅ 已套(2026-07-19) | DEV/STG 皆套且對帳綠(STG 兩表 + cm_app GRANT + schema_migrations 實查);POC 未套(累計缺 4 支:fr049 快照欄/fr0491/perf indexes/fr050,隨 POC 部署日補),見 docs/claude/sql-migration-conventions.md |
| E2E 場景 | 未派工 | test repo 尚無 FR-050 對應 feature/step,待排入 site-regression 套件 |
| design §6 驗收情境完整 live 驗證 | 只做過 API 面 | design.md §6 六情境(1. planning↔︎audit_planning 往返含新 snapshot;2. auditing 回退 AR 保留可改;3. 非 manager/reason 空擋;4. closed 無入口;5. 時間軸多次往返正確;6. 零 DELETE 對帳)目前驗證深度:情境 3/4 有 route-level smoke + 單元測試覆蓋較完整;情境 1/2/6 需要真實跑一輪「推進→回退→重推」的完整 live 資料流(含確認重推後產生新 snapshot、AR 保留可編輯、DB 對帳零 DELETE)尚未做,只驗證了 handler 呼叫鏈與 mock 層級行為 |
| §4.4 選項 A 未來反悔條件 | 若日後 OSCAL 文件生命週期需要通用 superseded 語意(非僅本案業務場景),才需重新評估選項 A(動套件列舉) | 目前無觸發跡象 |