FR-038 收尾弧 — 稽核 + POA&M 階段完成 換 session Handoff(2026-06-17)

項目 內容
緣由 接續 FR-038 round-flow,把生命週期最後兩階段(audit / poam)的 FE 遷到 v2 round-scoped,並補 AP→AR 溯源、風險 CRUD、我的稽核
BE branch feature/oscal-refactor勿切 branch
FE branch 同名 feature/oscal-refactor~/Projects/Billows/Audit-Manager/compliance-manager-fe/
套件 jedi-oscal-v2~/Projects/Jedicogy/module/jedi-python-package/jedi-oscal-v2/,editable .pth,改完重啟 BE 生效)
🔴 狀態 三 repo 全部未 commit、未 push(working tree);BE 已於 2026-06-17 以最新改動重啟(可直接測 POA&M);收尾文件(changelog/SUMMARY/Notion)尚未做(等 user 令)
下一棒 POA&M 階段端到端實測(finalize → 缺失改善 → 結案),+ 補里程碑負責人指派
接手前必讀 本文件全讀 + implementation-plan-final-stages.md

🧭 原始需求 / WHY(先懂再動)

大圖:FR-038 把 OSCAL v1→v2。本弧處理生命週期最後兩階段 FE 遷移 + AR 溯源。OSCAL 評估鏈:Catalog→Profile→SSP→AP→AR→POA&M。

這弧拍板的關鍵決策

  1. 判定粒度收斂到「控制層」(user 2026-06-17 拍板):每控制一筆 finding(不展開 AO)。理由:跟舊流程一致、CMMC+ISO 通用(ISO 無 AO)、POA&M/覆核 per 控制乾淨、舊三欄 UI 可沿用。AO 細節改放 observation。
  2. manager 全域 override:manager 可推進/操作所有階段(含 auditor 專屬的 audit/poam)。
  3. AR 溯源比照 OSCAL:受評對象用 result.assessment-subjects[](新建 child table);風險鉤稽寫 OSCAL 原生 finding.related_risks[](dual-write)。

冷接自檢 4 問(答不出回去讀):

  1. 判定是 AO 層還控制層?→ 控制層(init_ar_matrix 每控制一筆 finding;舊輪是 AO 級,FE 用聚合相容)。
  2. 受評對象/風險鉤稽存哪?→ oscal.ar_assessment_subjects(result.assessment-subjects)/ finding.related_risks(OSCAL 原生)+ join table assessment_finding_risks(查詢索引)。
  3. 為何 manager 能做 auditor 的事?→ 全域 override(4 處:stage_advance / AP service / AR service / round 狀態 _check_role)。
  4. POA&M item 從哪來?→ finalize_audit → generate_from_findings(not_met finding → poam item,related_findings 軟引用)。

§0 接手讀序

  1. 🔒 本文件「WHY」全讀 + 答出自檢 4 問
  2. docs/features/FR-038-2606-oscal-redesign/implementation-plan-final-stages.md(本弧 plan)
  3. 主嫌路徑檔(見 §5 檔案地圖)
  4. 先重啟 BE + FE reload(§4 pre-flight)再動

§1 目前狀態(已完成,分 verified / 待重啟驗證)

BE + jedi-oscal-v2(全部需重啟 BE 生效;import smoke 已過)

  • 進階段三修count_reviewed_controls len bug、audit_round_app_service._to_dto datetime 序列化、stage_advance_service manager override(line 110/286)
  • frozen SSP resolverdomain/oscal/service/ssp_project_resolver.py_resolve_project_id(living + frozen round 兩鏈);DI oscal_containers.py 注入 project_audit_round_domain_service;repo/domain 加 get_by_ssp_id
  • AR 溯源:新表 oscal.ar_assessment_subjects(migration scripts/sql/2026-06-17-ar-assessment-subjects.sql 已套 DEV;stg/poc/prod 待辦)+ 套件 6 新檔(model/entity/query/mapper/repo if+impl)+ assessment_result_service.add_result(assessment_subjects=) / list_result_subjects
  • start_auditing echoinit_ar_matrix_for_round 把 AP 受評對象→AR subjects、AP tasks→ar_results.assessment_log判定收斂控制層init_finding_matrix(control_ids)
  • observation.subjects:create_observation 收 subjects(route+schema 已通);get_findings 回 assessment_subjects
  • manager override 補齊assessment_plan_app_service._check_auditorassessment_result_app_service._check_auditoraudit_round_app_service._check_role 全放行 manager
  • 我的稽核重建infra/grc/repository/auditor_dashboard_query.py 2A dark→查 v2 audit_round(+ verdict 統計);serializer 加 round_uid
  • 風險 CRUD:AR app service update_risk/delete_risk + 套件 assessment_risk_service.update_risk/delete_risk;route PUT/DELETE /audit-round/<r>/ar/risk/<risk_uid> + UpdateRiskRequest
  • 風險鉤稽 dual-write(方案 A)link_risk_findings/delete_risk 同步寫 OSCAL finding.related_risks[]_set_finding_related_risk helper)+ join table;list_riskslinked_findings(finding_uid+control_id)

FE(整頁重整生效,不需重啟 BE

  • 稽核頁 RoundAuditReviewView.vue(新):三欄(沿用 AuditTreeNav+AuditControlRef + v2 控制層判定面板);判定 Tab(符合/不符合/待判定 + 說明 + 觀察帶受評對象)+ 風險 Tab;左樹預設全展開 + 判定圓點(met→pass/not_met→fail);字型放大一級;證據接真實來源(檔案/連結 from job-evidences、問卷 from job detail task_surveys 去重);AO 級舊輪用聚合相容(任一 AO not_met→控制 not_met,判定寫回全部 AO finding)
  • 風險卡片:檢視/編輯合一(標題+等級+描述+來源一次存)、刪除有 confirm、「來源」chips
  • POA&M 頁 RoundPoamView.vue(新):三層(項目→矯正措施→里程碑),尚未 runtime 測
  • 稽核計畫填寫頁 RoundApAuthoringView.vue(本弧+前;受評控制項/對象/行程;唯讀模式 by user)
  • 我的稽核 MyAuditsView.vue:導 round-scoped
  • router 加 project-audit-review-round / project-poam-round;總覽按鈕 isRoundRoute 派發

§2 踩過的雷 / 必懂 gotchas(別重蹈)

  1. 控制層 vs AO 級輪並存:新輪 = 控制層(1 finding/控制);舊輪(如 ar_result 467)是 AO 級(N finding/控制)。FE 用聚合相容兩者。測 POA&M 建議用新控制層輪(舊輪 finalize 會 per-AO 生 POA&M item)。
  2. manager override 在 4 處,少一處就卡(曾漏 audit_round_app_service._check_role → start_auditing 報「不具稽核員角色」)。
  3. 多 auditor 閘門名稱不同_check_role(round) vs _check_auditor(AP/AR) vs stage _resolve_main_roles
  4. finding state 兩 tokentarget_status_state 欄 = OSCAL product token(satisfied/not-satisfied/pending);target_status.product_state JSONB = FindingState 值(met/not_met/pending)。get_findings 的 state 用後者;FE 用 met/not_met/pending。AuditTreeNav 圓點吃 v1 詞彙(pass/fail) → 需 toTreeVerdict 對應。
  5. 證據來源/job-evidences?job_execution_uid= 只回檔案/連結,問卷在 job detail 的 task_surveys(一份問卷多指派=多 task_survey,需去重)。
  6. dual-write 同步:改 risk↔︎finding 連結務必同時維護 join table + finding.related_risks(已封裝在 link_risk_findings/delete_risk)。
  7. 問卷 Dialog/embed 已還原:曾試過 Dialog+iframe+AppLayout embed,因難讀已 revert → 問卷現在開新分頁。勿再加回除非 user 要。

§3 下一棒(POA&M)

3.1 端到端實測(主任務)

重啟 BE + 用新控制層輪:planning → ap_authoring →(啟動稽核)→ audit(判定不符合 + 風險鉤稽)→(finalize)→ 缺失改善

  • round.status=remediationround.poam_id 有值、oscal.poam_items 筆數 = not_met 控制數、poam_item.related_findings 指回 finding
  • POA&M 頁加矯正措施 + 里程碑 → 里程碑全 done → 結案(close_round 強制 all_items_closed)→ closed

3.2 待補:里程碑「負責人指派」(本弧 defer)

  • 為何 deferRoundPoamView.addMilestone 目前只送 {title, target_date}。BE add_milestoneassignee_user_idint user_id,但 FE 手上的 participants 是 user_uid 字串 → 型別不一致,需做 user_uid→user_id 對應(查 users 或讓 BE 收 uid)。
  • 做法建議:BE add/update_milestone 改收 assignee_user_uid(內部轉 id),FE 用 participants 當候選;或 FE 拿 user_id。

§4 Pre-flight(必跑)

cd ~/Projects/Billows/Audit-Manager/compliance-manager-be
git branch --show-current                 # 應 feature/oscal-refactor
git status --short | grep -vE '^\?\? '     # 對照 §6 我的改動清單
# import smoke(sandbox 無法完整 boot)
set -a; source .env; set +a; export GITLAB_API_VERSION=4 GITLAB_URL=x GITLAB_PRIVATE_TOKEN=x GITHUB_PRIVATE_TOKEN=x
.venv/bin/python -c "import api.project, app.grc.service.assessment_result_app_service; print('OK')"
  • 請 user 重啟 BE(service/repo/套件改動無 hot reload;服務 user 自己起)
  • FE 整頁重整(router/i18n 改動);FE build 驗:cd ~/Projects/...-fe && npm run build:DEV

§5 檔案地圖(為何 read)

BEassessment_result_app_service.py(AR 判定/觀察/風險/溯源核心)、audit_round_app_service.py(start_auditing/finalize/close_round/launch_reverify + _check_role)、ssp_project_resolver.py(frozen SSP 反查)、auditor_dashboard_query.py(我的稽核)、assessment_plan_app_service.py(AP 寫入 + _check_auditor)、stage_advance_service.py(推進 override) 套件ar/assessment_result_service.py(add_result/list_result_subjects)、ar/assessment_risk_service.py(update/delete_risk)、ar/oscal_ar_assessment_subjects*(新 child table 6 檔) FERoundAuditReviewView.vue(稽核三欄主檔)、RoundPoamView.vue(POA&M)、MyAuditsView.vueProjectAuditorOverview.vue(按鈕派發)、AuditTreeNav.vue(expandAll + 圓點)


§6 未 commit 改動清單(我的,三 repo;勿用 -am,顯式 git add

BE(M):api/grc/serializers/auditor_dashboard.pyapi/project/__init__.pyapi/project/routes/audit_round_route.pyapi/project/serializers/audit_round.pyapp/flow_engine/service/stage_advance_service.pyapp/grc/service/{assessment_plan,assessment_result,audit_round}_app_service.pydi_containers/oscal/oscal_containers.pydomain/grc/repository/i_project_audit_round_repo.pydomain/grc/service/project_audit_round_domain_service.pydomain/oscal/service/ssp_project_resolver.pyinfra/grc/repository/{auditor_dashboard_query,project_audit_round_repo_impl}.py(??)scripts/sql/2026-06-17-ar-assessment-subjects.sql

⚠️ BE 的 pyproject.toml / docs/features/README.md / proposal.html 不是我改的(pre-existing / user in-flight)— 勿一起 commit。

套件(M):jedi_oscal_v2/app/service/ar/assessment_result_service.py.../assessment_risk_service.py;(??)jedi_oscal_v2/{domain/entity/ar,domain/repository/ar,infra/mapper/ar,infra/model/ar,infra/repository/ar}/*ar_assessment_subjects*(6 檔)

⚠️ 套件的 catalog_service.pyoscal_io_service.pytests/../jedi-*/CLAUDE.md 不是我改的 — 勿一起 commit。

FE(M):src/components/grc/AuditTreeNav.vuesrc/config/locales/index.jssrc/config/router/index.jssrc/views/project/MyAuditsView.vuesrc/views/project/ProjectAuditorOverview.vue;(??)src/views/project/{RoundApAuthoringView,RoundAuditReviewView,RoundPoamView}.vuesrc/config/locales/i18n/{en,zh-tw}/{ap-authoring,round-audit-poam}.json


§7 行為規範提醒

  • 不切 branchpush 等 user 明示;三 repo 各自 commit、顯式 git add、禁 -am
  • 改 BE service/repo/套件 → 提醒 user 重啟(服務 user 自起、Claude 不啟動)
  • 動 FE 前讀 FE CLAUDE.md;不晶晶體;plan 假設先 verify
  • 收尾類動作等 user 明確下令:changelog / SUMMARY / design §11 / Notion / commit 收尾 —— 目前都還沒做

§8 不在本期 scope / follow-up(勿順手做,列著)

  • severity OSCAL characterizations facets(目前簡化 {"severity":...},非 likelihood×impact facets)— user 已知,列 follow-up
  • assessment-assets(稽核工具/平台)— OSCAL 有,BE 無端點
  • 我的稽核 evidence 統計(目前 0/0)
  • ISO 27001 落地差異 analysis 文件(user 說最後再補;Notion 已有「稽核生命週期設計評估」討論頁)
  • project_start 重複建 IR root cause(前弧 follow-up)
  • stg/poc/prod 套 2026-06-17-ar-assessment-subjects.sql

§9 給 fresh session 的超短 prompt

讀 docs/features/FR-038-2606-oscal-redesign/handoff/2026-06-17-final-stages-audit-poam-handoff.md,
先答冷接自檢 4 問(判定=控制層 / 溯源存哪 / manager override 4 處 / POA&M item 來源)再開工。
本弧已完成稽核+POA&M FE(v2 round-scoped)+AR 溯源+風險 CRUD+我的稽核(全在 working tree、未 commit)。
下一棒:請 user 重啟 BE → 用「新控制層輪」端到端實測 POA&M(finalize→缺失改善→結案),
查 round.status/poam_id/poam_items/related_findings;再補里程碑負責人指派(user_uid→user_id 對應,見 §3.2)。
不切 branch、push 等 user、收尾等 user 令。