FR-142 · 討論稿 · 2026-10-16

稽核結果逐 AO 判定重做

左樹三層+控制項總覽、一次一條評估目標(佐證→稽核發現→稽核結果→風險)、稽核報告頁籤寫第 7 章、Excel 只關聯檔案、報告 Word/PDF

現在的稽核判定頁「一個控制項一個判定」、畫面擠、風險要跨頁建;稽核人員現場拿的是 FR-141 那份逐評估目標(AO)的稽核計畫,照表逐條查,結果也該逐條記。本案把判定頁整個重做:左樹到評估目標三層、中間一次一條評估目標,依序填佐證、稽核發現、稽核結果、風險;控制項結論由評估目標自動推算;「稽核報告」頁籤只寫第 7 章,預覽與匯出才組完整報告;Excel 就是稽核計畫那份往後加結果欄,佐證只關聯檔案。資料照 OSCAL 評估結果(AR)的標準欄位存,順手修掉套件三處匯出不合規。D1~D12 已裁、雛形定版,請先開 雛形 點一遍再看規格。

D1~D12 已裁(2026-10-16) 雛形定版 動兩支套件:jedi-oscal-v2、jedi-compliance-audit 站在 FR-141(已併入 feature/FR-139)之上

雛形審過、拍板後寫 design.md,本稿不再改寫。

狀態:討論稿定版(D1~D12 已裁,雛形定版,待落 design.md) | 日期:2026-10-16 | 母卡:CM-2818 | 雛形卡:CM-2819 | 雛形:prototype/index.html

路徑慣例:BE 路徑相對 compliance-manager-be/;pkg/ 代表 ~/Projects/Jedicogy/module/jedi-python-package/<套件>/<套件底線名>/;FE 路徑相對 compliance-manager-fe/。

名詞:評估目標=AO,下文兩詞混用;AR=稽核結果(assessment results),OSCAL 評估層第二個文件;AO=評估目標,一條控制項底下的檢查項目,全系統用 part_id 當鍵(<控制項代碼>_obj.N);finding=OSCAL AR 裡「一條 AO 的判定」物件;observation=稽核人員看到的事實與佐證;risk=風險,可連多條 finding;remediation=風險底下的處置建議;attestation=稽核人員署名的文字陳述;稽核次=FR-140 的概念,一輪內每做一次稽核一筆,各自一份 AP 與一筆 AR result。

§1

變更紀錄

日期 變更 對應
2026-10-16 定版:雛形經決策者六輪調整後定案。D2 風險改「只在不符合時出現」、拿掉風險總覽頁籤;D3 稽核報告頁籤只留第 7 章、預覽才組完整報告;新增 D6~D12(左樹到評估目標與控制項總覽、評估目標頁順序、佐證來源與採用、Excel 只關聯檔案、結案全鎖、附件橫式中文、表單文案);P1~P3 併入定案 母卡 CM-2818
2026-10-16 初稿:需求、三份參考檔結構、已裁 D1~D5、現況盤點(含套件三處匯出不合規)、OSCAL 落點、Excel 契約、報告匯出、拆卡草案、雛形第一輪 母卡 CM-2818

§2

分工概述(30 秒版)

整案一句話:判定頁換成左樹到評估目標、中間一次一條評估目標(佐證→稽核發現→稽核結果→風險),控制項結論自動推算;「稽核報告」頁籤只寫第 7 章,預覽與匯出才組完整報告;Excel 是稽核計畫那份往後加結果欄,佐證只關聯檔案。

棒 做什麼 產出 完成怎麼判定(決策者親手做什麼、看到什麼)
0 雛形 純前端假資料:評估目標判定、稽核報告兩頁籤,匯入預覽,範例 Excel prototype/+sample/*.xlsx ✅ 已定版(2026-10-16)
1 套件 AR 修正+評估目標層矩陣 jedi-oscal-v2:finding 狀態改存 OSCAL status.state/reason/implementation-status、risk 等級改 facets 陣列、finding↔︎risk 連結匯出改讀連結表、remediation lifecycle 必填、新增 observation/attestation service;jedi-compliance-audit:新稽核次不預建 finding、控制項結論規則收斂成一支 套件 migration、service、匯出合規 DEV 開新稽核次,oscal.assessment_findings 該 result 筆數=0;判一條不符合後匯出 OSCAL JSON 用官方 schema 驗過
2 BE 評估目標判定端點 讀取(合成逐評估目標列+候選佐證+控制項結論+統計)、整批存、稽核報告第 7 章、結案守門與鎖定、佐證凍結 新 app service 檔、route、schema Swagger 存三條評估目標再讀回一致;結案 API 在有未判定或第 7 章空白時回 412;結案後寫入回 409
3 FE 頁面重做 新頁殼(左樹三層、控制項總覽、評估目標頁、稽核報告頁籤、報告預覽)、舊 RoundAuditReviewView.vue 退役 FE 新檔、路由 對照雛形逐頁操作一遍,每個動作對應後端真資料
4 Excel 匯入匯出 稽核計畫 workbook 加結果欄讀寫、佐證檔名比對、匯入預覽就地處理 ar_workbook_*.py、FE 預覽模式 匯出改兩格與一個檔名匯回,預覽標出、確認後畫面更新;寫錯檔名預覽要求處理
5 報告 Word/PDF 沿用 FR-141 docx 範本,正文直式 1~7 章、附件橫式 8 欄;匯出三選一 ar_report_export_service.py、範本 Word 開檔看到 1~7 章與橫式附件,判定為中文
6 FR-140 對齊與選單 縮範圍規則讀評估目標層 finding;判定與風險等級選單 seed pass_scope_rule.py、seed migration 第 2 次內稽新 AP 只剩不符合評估目標所屬控制項;後台看到新選項

依賴:1 先做(2~5 都靠它的資料形狀)→ 2、4、5 可平行 → 3 等 2 → 6 等 1。全部接在 feature/FR-139(FR-141 已併入)。

%%{init: {'theme':'base','themeVariables':{'primaryColor':'#E2F0F1','primaryTextColor':'#14201F','primaryBorderColor':'#0E7C86','secondaryColor':'#EEF2F3','secondaryTextColor':'#14201F','tertiaryColor':'#FBFCFC','tertiaryTextColor':'#14201F','lineColor':'#4A5A5C','textColor':'#14201F','mainBkg':'#E2F0F1','nodeBorder':'#0E7C86','nodeTextColor':'#14201F','edgeLabelBackground':'#FBFCFC','titleColor':'#14201F','clusterBkg':'#FBFCFC','clusterBorder':'#E4EAEB','actorBkg':'#E2F0F1','actorTextColor':'#14201F','actorBorder':'#0E7C86','actorLineColor':'#C7D1D2','signalColor':'#4A5A5C','signalTextColor':'#14201F','labelBoxBkgColor':'#EEF2F3','labelBoxBorderColor':'#C7D1D2','labelTextColor':'#14201F','loopTextColor':'#14201F','noteBkgColor':'#F6EBD5','noteTextColor':'#14201F','noteBorderColor':'#9C6B12','activationBkgColor':'#EEF2F3','activationBorderColor':'#C7D1D2','sequenceNumberColor':'#FFFFFF'}}}%%
flowchart LR
    P[棒 0 雛形<br/>CM-2819] --> R{決策者審}
    R --> D[design.md<br/>開 1~6 的卡]
    D --> B1[棒 1 套件 AR 修正<br/>AO 層矩陣]
    B1 --> B2[棒 2 BE 判定端點]
    B1 --> B4[棒 4 Excel]
    B1 --> B5[棒 5 報告]
    B2 --> B3[棒 3 FE 三頁籤]
    B1 --> B6[棒 6 FR-140 對齊]
    F141[FR-141 已併入<br/>feature/FR-139] -.骨架、Excel、docx 範本.-> B3
    F141 -.-> B4
    F141 -.-> B5
圖 1 — 棒次依賴

§3

需求

決策者原話(2026-10-16)

目前稽核階段的 UI 也是只能針對控制項來填寫,應該也是要比照稽核計畫,要 by AO,且針對每項 AO 去寫他通過不通過、finding、風險,以及建議等等 OSCAL 需要的資訊;該控制項如果有一個 AO 不符合或是有風險,那就表示該控制項不符合,預設就幫控制項帶不符合。 這邊也要可以用 Excel 匯入匯出的方式,讓稽核人員可以利用 Excel 去填寫,內容可以參考稽核計畫,因為稽核人員應該就是會拿著稽核計畫那份去現場按照表做稽核,所以要用它來延伸需要欄位來填寫。 這邊的 UI 要整個重新設計,現在的也是有夠難使用,畫面小小的、填寫處只有一點點位置。請參考 FR-141 的逐項計畫填寫處那邊的模式:左側導航模式、中間改成稽核專用的;再多開一個 tab 是拿來寫文字版稽核結果的,就是接續原本 AP 的 word 的第 7 大項,1~6 看有沒有需要放在畫面上讓 user 參考,完成後就可以匯出一份 word/PDF 報告了。 資料盡量放入 OSCAL 正確的欄位,不要亂使用,一樣可以修改套件。

三份參考檔長什麼樣

亞航內部稽核報告(docx)

八個編號段:1 依據、2 目的、3 稽核單位、4 稽核日期、5 稽核範圍、6 稽核方法、7 稽核結果、8 附件(只有一行標題)。第 7 段是三條純文字結論(7.1 現場網路與架構圖一致、7.2 實體管控依 SSP 實施、7.3 各項實務要求皆取得證據),沒有表格、沒有缺失統計、沒有建議——因為該次全 MET。1~6 段與 FR-141「計畫概要」頁 1:1。

亞航附件稽核紀錄表(xlsx)

一張表 59 列(一列一條 AO)、8 欄:序號、索引號(隱藏)、實務要求、執行說明(只在控制項第一列填)、控制目標(AO)、「Status實作狀態」(實為查核方法與指引)、Evidence佐證資料、稽核結果。59 筆全 MET,沒有不符合樣本、沒有發現/風險/建議欄。沒有 part_id,對位靠「同索引號第幾列」;索引號尾端有多餘空白。

對照 FR-141 範例 Excel:兩份的 AO 排法一致(每 AO 一列、控制項層欄只在第一列填),顧問附件比 FR-141 多的只有「佐證資料」「稽核結果」兩欄。所以「結果檔」直接沿用 FR-141 的列結構、用隱藏的 part_id 當比對鍵,後面加欄即可。發現/風險嚴重度/風險說明/建議四欄兩份都沒有,值域由本案定。

新畫面長什麼樣

雛形 prototype/ar-authoring.html 兩個頁籤:

  1. 評估目標判定
    • 左樹三層:控制族群 → 控制項 → 評估目標,每層最前面一顆燈號(符合綠實心、不符合紅實心、不適用灰圈加斜線、未判定空心),hover 顯示稽核結果與全文;評估目標文字最多兩行。篩選:全部/未判定/不符合。
    • 點控制項=控制項總覽:控制項結論、判定依據(例「評估目標 [a][c] 不符合」)、四類計數,下方逐評估目標列稽核結果、稽核發現、風險等級,點列進入該評估目標。
    • 點評估目標=評估目標頁,由上往下:稽核計畫(摺疊參考)→ 佐證 → 其他佐證 → 稽核發現 → 稽核結果* → 風險(只有判不符合才出現,符合時留「+ 新增風險」連結)。底部上一條/下一條在評估目標間跳。
  2. 稽核報告:只有第 7 章「稽核結果」一個編輯器,旁邊「帶入不符合事項」「預覽報告」。預覽開全螢幕:第 1 頁直式正文 1~7 章,第 2 頁橫式附件 8 欄,右上角下載 Word/PDF。

頁首:匯入 Excel、匯出(稽核報告/稽核結果工作表(Excel)/全部檔案)、儲存、結案;頂部六格統計(控制項、符合、不符合、不適用、未判定、風險)。


§4

已裁決策

D1 判定值域=符合/不符合/不適用三值,加「未判定」當初始狀態但不算判定

  • 畫面與 Excel 四個選項都看得到;Excel 空白=未判定;送出結案時擋「還有未判定」。
  • OSCAL 存法:符合/不符合 → finding.target.status.state=satisfied/not-satisfied;不適用 → finding.target.implementation-status.state=not-applicable,status.state 同時填 satisfied、reason=other 讓匯出合規;未判定=不建 finding,不落假值。
  • 清掉套件自創的 pending/not-applicable 狀態 token 與 target_status={"product_state":…}。

為什麼:稽核人員現場一定有「還沒查到」的狀態,不能逼他先選;但 OSCAL 的 status.state 是封閉值域(只有 satisfied/not-satisfied),「未判定」「不適用」沒有對應值,硬塞進去匯出就不合規。implementation-status 官方語意是「控制項實作到什麼程度」,not-applicable 是它的正規值,放這裡最貼。

被排除:維持現狀四值全進 status.state(匯出不合規);「不適用」改成不建 finding(報告附件要印 N/A,沒 finding 印不出來)。

D2 風險在評估目標上就地填,只有判不符合時出現;不設風險總覽頁籤

  • 評估目標頁判「不符合」時展開風險區:風險等級(無/低/中/高)、風險說明、改善建議。判符合時收起,留「+ 新增風險」連結給「符合但有疑慮」的少數情況。
  • 存法:每條填了風險的評估目標自動生一筆 risk(status=open),用 assessment_finding_risks 連結表綁到該 finding;改善建議存 risk.remediations[] 一筆 lifecycle=recommendation。
  • 判準「有風險」=風險等級或風險說明任一有值;有風險的評估目標,所屬控制項判不符合(D5)。

為什麼:顧問習慣一列填完;「先建風險再勾評估目標」是現在頁面難用的主因。大多數評估目標是符合,風險區收起畫面短一半。

被排除:維持「風險獨立建、再勾」為主路徑(難用);風險總覽頁籤與合併多筆(雛形第一版有,決策者看過後拿掉:風險已逐評估目標呈現、報告附件也逐列印,合併功能 Excel 無法來回)。

D3 「稽核報告」頁籤只寫第 7 章;1~6 章與附件只在預覽與匯出時組出完整報告

  • 頁籤只有一個大編輯器,像在 Word 打第 7 章一樣寫,想分幾點分幾點。
  • 「帶入不符合事項」把判不符合的評估目標依「控制項代碼 標題 [評估目標]:稽核發現/風險(等級)/改善建議」格式接在現有內容後面;無不符合時提示「無不符合事項」。
  • 「預覽報告」開全螢幕:第 1~6 章來自稽核計畫(FR-141 的 ap_terms_and_conditions 等),第 7 章為本編輯器內容,附件為逐評估目標結果表(D11)。
  • 存法:整段存 ar_results.attestations[] 一筆,parts[] 一個 part(name 固定 audit-conclusion),responsible-parties 帶稽核人員。

為什麼:1~6 章與附件放在頁籤裡頁面太長,使用者會誤以為沒地方寫;第 7 章才是這一頁要做的事。OSCAL 的 attestation 官方語意是「評估者寫的文字陳述」,比 result.description 或 remarks 貼切。

被排除:固定三個子節(看不懂);左右分欄唯讀 1~6 章(難看);1~6 章與附件全攤在頁籤裡(太長)。

D4 舊資料不遷移,只影響新開的稽核次

  • 稽核次開始時若該次 AR result 已有 finding(舊控制項層)就維持舊讀法;新開的稽核次一律 AO 層。判斷依據:finding 的 target_id 是否含 _obj.。
  • 舊頁 RoundAuditReviewView.vue 退役後,既有控制項層稽核次用新頁唯讀顯示(每控制項一條合成卡),不開放編輯。

為什麼:舊輪資料只有 DEV 與少數測試專案;把控制項判定拆到每條 AO 要猜,猜錯比不猜糟。FR-140 已有「每次稽核一筆 result」的分界點可借用。

D5 控制項結論不存欄位,由 AO 即時推導;三處各自實作收斂成套件一支

  • 規則:任一 AO 不符合或掛風險 → 不符合;全部 AO 不適用 → 不適用;還有未判定 → 未判定;其餘 → 符合。
  • 落點:jedi-compliance-audit 一支純函式(ar_import/aggregation.py 的 aggregate_verdict 擴充「掛風險」條件),FE 不再自己算、FR-140 縮範圍規則改呼叫它。
  • 統計(控制項數/符合/不符合/不適用/未判定/風險數)由 BE 回傳,FE 只顯示。

為什麼:現在 FE(RoundAuditReviewView.vue:411)、BE 匯入(aggregation.py:10)、縮範圍(pass_scope_rule.py:12)三套規則各寫一次,「掛風險也算不符合」是新條件,三處改必漏。OSCAL AR 本來就沒有控制項層判定欄,存了反而要維護一致性。

D6 左樹到評估目標三層,點控制項看控制項總覽

  • 左樹:控制族群 → 控制項 → 評估目標,與專案規劃頁同(FR-141 稽核計畫只到控制項,是 FR-141 做淺了)。
  • 燈號放最前面,顏色加形狀區分四態,色弱可辨;hover 顯示「稽核結果:X」與全文;樹上方一列圖例。評估目標文字最多兩行。
  • 點控制項:中間顯示控制項總覽(結論、依據、計數、逐評估目標結果表);點表格列進評估目標頁;評估目標頁頁首有返回箭頭。
  • 中間頁首「控制項結論」保留文字膠囊。

為什麼:右側膠囊把評估目標與控制項說明擠到被截斷;中間一次只放一條評估目標,資訊才不會擠在一起;點控制項要看得到控制項結果。

被排除:膠囊放右側(擠);文字無限換行(樹太長);點控制項直接跳第一條評估目標(看不到控制項結果)。

D7 評估目標頁照稽核人員實際做事的順序:佐證 → 其他佐證 → 稽核發現 → 稽核結果 → 風險

  • 欄位:佐證(清單)、其他佐證(訪談、現場觀察等文字)、稽核發現、稽核結果*(四選一)、風險(D2)。
  • 「其他佐證」與佐證清單分開;拿掉檔案旁的備註框——要指出檔案哪一頁寫在稽核發現。

為什麼:稽核人員是先看證據、寫下看到什麼、最後才判過不過;第一版把判定放最上面等於先下結論。備註框與「其他佐證」太像,使用者分不出來。

D8 佐證=這條評估目標對到的任務佐證(檔案、連結、問卷),一張平的清單,預設全部採用,取消勾選=不採用

  • 來源:public.workflow_execution_control_mapping 對到該控制項/評估目標的任務,底下 compliance.job_evidences 類型 FILE/LINK/SURVEY 的項目,合成一張清單、同筆去重;不分任務顯示,每列後面標上傳者與日期。
  • 只有檔案、連結、問卷可採用;任務討論(job_execution_comments)與報告類型不列。
  • 「加入其他佐證」:從整個專案其他任務的佐證挑;「現場上傳」:稽核人員現場拍的照片,存為本次稽核的佐證,清單上標「現場」。
  • 「採用」的語意:記在稽核結果這邊,表示「本評估目標判定採用這些證據」,不改任務端資料、不標有效無效;同一份證據可被多條評估目標各自採用。
  • 判「符合」但沒有任何佐證:提示「未附佐證」,不擋。

為什麼:舊頁 RoundAuditReviewView 是「上面頁籤瀏覽、下面觀察表單另外多選關聯」兩塊;併成一張清單,看與勾在同一處。稽核人員不需要知道任務分組;討論是溝通紀錄、不是證據,有用的內容應寫進稽核發現。

被排除:自編證據池(第一版,未對應系統資料);依任務分組(看不出需要);討論可勾選採用(決策者裁:只供參考,後再裁拿掉);回到舊頁頁籤式(一條評估目標佐證通常三五筆,分頁籤要一直切)。

D9 Excel:與稽核計畫同一份四頁,計畫欄灰底唯讀,後接結果欄;佐證只關聯檔案

  • 結果欄:稽核結果、佐證檔案、其他佐證、稽核發現、風險等級、風險說明、改善建議。
  • 佐證檔案一行一個檔名,只含檔案與現場上傳;刪一行=不採用、加一行=採用。連結與問卷只在畫面設定,Excel 不出現也不讀。
  • 「可選清單」頁新增「佐證檔案」欄,列出專案內可關聯的檔名供複製。
  • 匯入時檔名比對專案檔案;對不到或同名多筆時,預覽頁就地處理:對應到某個檔案/改為其他佐證文字/略過。

為什麼:稽核人員不會照「類型:名稱」格式寫;檔名是唯一實際會出現在 Excel 的證據形式,也是亞航附件的寫法。

D10 結案=本次稽核整份鎖定

  • 結案守門三條:尚有評估目標未判定、不符合項目未填稽核發現(或有風險等級未填風險說明)、第 7 章未填寫。任一成立即擋,列出原因。
  • 通過後再確認一次;結案後判定、風險、佐證、第 7 章全部唯讀,畫面顯示「本次稽核已於 YYYY-MM-DD 結案,內容不可修改」。
  • 結案時凍結每筆採用佐證當下的版本(檔案記雜湊值與版本;連結記網址;問卷記填答快照識別),之後受稽單位更換檔案不影響稽核紀錄。
  • 要改只能在下一次稽核重做(FR-140 流程)。

為什麼:決策者原話「過了就過了,那不是結案報告,不然一直改等等會有爭議」。結案後產生 POA&M,若仍可改判定會與 POA&M 對不上。

D11 報告附件橫式 8 欄、判定印中文

  • 正文 1~7 章直式;附件獨立一節橫式(docx 分節換方向)。
  • 8 欄:序號、索引號、實務要求與執行說明(合一欄)、控制目標、查核方法:指引、佐證資料、稽核結果、稽核發現與風險(合一欄)。
  • 稽核結果印「符合/不符合/不適用/未判定」,不印 MET。不符合列淡紅底。
  • 預覽與匯出可取消「含稽核發現與風險」,取消後為亞航原表 7 欄。

為什麼:10 欄直式 A4 每欄不到 2 公分不可讀;合併兩組欄後與亞航原表寬度相近。

D12 表單文案用專業用語,不放說明句

  • 欄位、按鈕、提示訊息用表單慣用詞(佐證、稽核發現、稽核結果、風險等級、改善建議、選擇文件、上傳、結案、已儲存、匯入完成)。
  • 不放 placeholder 範例句、欄位旁說明句、頁首說明列;驗證訊息寫成「尚有 N 項評估目標未判定」「不符合項目須填寫稽核發現」這類格式。
  • 判定類 badge 與燈號全頁同一套樣式;不使用左側粗色邊框卡片(見 CLAUDE.md UI 禁令)。

§5

現況盤點:接入點 × 現況 × 本案動作

座標以 2026-10-16 為準,runner 開工先開檔核一次。FR-141 已完整併入 feature/FR-139(git merge-base --is-ancestor 成立),其頁面骨架、六支 app/flow_control/service/ap_*.py、docx 範本都在主工作樹。

① AR 資料模型(套件 jedi-oscal-v2,schema oscal,pkg/jedi-oscal-v2/infra/model/ar/)

表 現況 本案動作
assessment_results(oscal_ar.py:27) uid、metadata_id、status、import_ap_id、local_definitions 不改
ar_results(oscal_ar_results.py:25) 每稽核次一筆(FR-140);reviewed_controls NN、attestations/assessment_log JSONB 無任何 service 寫入 棒 1:加 attestation 寫入 service;reviewed_controls.control-objective-selections 寫入本次 AO 清單
assessment_findings(oscal_ar_finding.py:26) target_type 永遠 objective-id 但新輪 target_id 存 control_id;target_status_state 存自創 token(pending/not-applicable);target_status JSONB 存 {"product_state":…};沒有 target.status.reason/implementation-status/target.description 欄 棒 1:每 AO 一筆、target_id=part_id;target_status JSONB 改存 OSCAL 形狀 {state, reason, remarks};加 implementation_status JSONB;description 存判定理由
assessment_observations(oscal_ar_observation.py:26) 欄位齊全(methods NN、relevant_evidence、subjects、collected);無 service;finding→observation 只有 JSONB 軟參照 棒 1:加 observation service;每條有發現或佐證的 AO 一筆,methods 從 AP activity 的方法帶、relevant_evidence[].description 放佐證文字
assessment_risks(oscal_ar_risk.py:25) characterizations 被寫成 {"severity":…}(assessment_risk_service.py:99-100),不是 OSCAL 陣列形狀 棒 1:改 [{origin:{actors:[稽核人員]}, facets:[{name:'severity', system:'http://csrc.nist.gov/ns/oscal', value:'高'}]}]
assessment_finding_risks(oscal_ar_finding_risk.py:25) link_findings 只寫這張表;匯出讀 finding.related_risks JSONB,沒同步,service 建的關聯匯出會消失 棒 1:寫連結表時同步回填 JSONB(或匯出改讀連結表,二擇一,建議後者)
assessment_remediations(oscal_ar_remediation.py) lifecycle 可空、註解寫 recommendation/required;官方必填且值域 recommendation/planned/completed 棒 1:NOT NULL+CHECK 三值;建議一律 recommendation
ar_assessment_subjects AR 層受評對象 不改

② 套件服務與主專案端點

元件 現況 本案動作
pkg/jedi-oscal-v2/domain/service/ar/ar_finding_matrix_service.py:40-48 init_finding_matrix 每個 id 一筆 finding、初始 pending;_STATE_TO_TOKEN 四值對照 棒 1:初始化不建 finding(未判定=無 finding);upsert 改寫 OSCAL 形狀
pkg/jedi-oscal-v2/app/service/io/oscal_io_service.py:1603-1608 匯出時 target_status 有值就原樣吐進 target.status 棒 1:改組 {state, reason}+implementation-status
pkg/jedi-compliance-audit/.../assessment_result_app_service.py(860 行,超標) init_ar_matrix_for_round(:204)傳 control_ids;judge_finding(:536);observation/risk/remediation CRUD(:572~:802);finalize_assessment(:834)看 pending 數擋 棒 1:init 改傳 AO part_id 清單;棒 2:新開檔 ar_objective_app_service.py 放整批存、統計、結案守門,不往 860 行裡加
pkg/jedi-compliance-audit/.../ar_import/aggregation.py:10 aggregate_verdict 四規則,只有 FR-044 匯入在用 棒 1:加「掛風險」條件,成為 D5 唯一規則
pkg/jedi-compliance-audit/.../pass_scope_rule.py:12 carried_control_ids:AO 沒自己的 finding 時退回控制層 棒 6:直接讀 AO 層 finding+D5 規則
主專案 route api/project/routes/audit_round_route.py:235-395 /audit-round/<round_uid>/ar/findings(GET)、finding/<uid>(PUT 單筆)、observations/risks CRUD、risk/<uid>/findings(PUT) 棒 2:加 PUT …/ar/objectives(整批)、PUT …/ar/attestation、GET …/ar/summary、POST …/ar/finalize 守門改版;舊單筆端點留給舊稽核次
ar_import_route.py+ar_import_app_service.py(621 行)+airasia_cmmc_l1_ar_v1.py FR-044 的亞航格式 xlsx 匯入(序號、索引號、實務要求、說明、AO、方法、佐證、稽核結果) 棒 4:新主路徑是 FR-142 格式(有 part_id);亞航原格式 parser 留作「沒有 part_id 的舊檔」退路

③ FE 現況

元件 現況 本案動作
src/views/project/RoundAuditReviewView.vue(1,083 行,超標) 路由 /project/projects/:id/round/:roundUid/audit;兩頁籤「控制項稽核判定」「風險」;讀 ao_findings 聚合成控制項狀態(:409-424)、存檔把同一判定寫到該控制項全部 finding(:551-555);風險建在「風險」頁籤再勾 finding 棒 3:全新檔 RoundAuditResultView.vue+ar-result/ 子元件(左樹、控制項總覽、評估目標頁、稽核報告、報告預覽),路由改指;舊檔退役(D4 舊稽核次用新頁唯讀)
src/components/grc/ar-import/ArImportDialog.vue(720 行) FR-044 匯入對話框 棒 4:改成預覽模式(同 FR-141 做法,不另開清單)
FR-141 的 ObjectiveTab.vue 等左樹右表單元件 已在主工作樹 棒 3:抽共用(左樹、控制項頁首、上一條下一條)或直接 copy,由 runner 看耦合度決定

④ 可沿用的匯出匯入能力

能力 座標 本案動作
稽核計畫 Excel 讀寫六支 app/flow_control/service/ap_workbook_{layout,writer,reader,diff,export_service,import_service}.py 棒 4:layout 加 COL_VERDICT…COL_REC 六欄常數;writer/reader 加結果欄;diff 加結果欄比對;新開 ar_workbook_export_service.py/ar_workbook_import_service.py 組合
報告稿 docx+pdf app/flow_control/service/ap_docx_generator.py、ap_report_export_service.py、範本 app/oscal/templates/ap/ap_report_template.docx、SspLibreOfficeConverter 棒 5:範本複製成 ar_report_template.docx(第 7 章佔位改真內容、附件表橫式加欄);新開 ar_report_export_service.py
解析暫存 oscal.ap_docx_parse_jobs,source_type 區分 棒 4:source_type='ar_xlsx'

§6

資料模型草案

OSCAL 落點(AR,v1.2.2)

畫面欄位 OSCAL 落表
稽核結果 result.findings[](每評估目標一筆):target.type=objective-id、target.target-id=part_id、target.status.state=satisfied/not-satisfied、target.status.reason=pass/fail/other、target.implementation-status.state=not-applicable(不適用時);未判定=不建 finding assessment_findings:target_id、target_status(JSONB 改 OSCAL 形狀)、新欄 implementation_status
稽核發現 finding.description(必填;符合且空白時系統補「經檢視佐證,符合本評估目標」)、finding.title=評估目標文字 assessment_findings.description/title
佐證(採用的檔案、連結、問卷、現場上傳) observation 一筆:methods=EXAMINE、relevant-evidence[] 每筆 href 指向該系統物件(檔案預覽、連結網址、問卷填答)、description=名稱;collected=存檔時間;finding 用 related-observations 連 assessment_observations(relevant_evidence JSONB)
其他佐證 observation 另一筆:description=文字、methods 照稽核計畫該評估目標的查核方法映射(訪談→INTERVIEW、文件檢查/現場觀察→EXAMINE、測試/設定比對→TEST) assessment_observations
風險等級 risk.characterizations[]:{origin:{actors:[稽核人員]}, facets:[{name:'severity', system:'http://csrc.nist.gov/ns/oscal', value:'低/中/高'}]} assessment_risks.characterizations(陣列)
風險說明 risk.title(取說明前段)、risk.description=risk.statement=說明全文、risk.status=open assessment_risks
改善建議 risk.remediations[] 一筆:lifecycle=recommendation、title/description=建議文 assessment_remediations
評估目標↔︎風險 finding.related-risks[] assessment_finding_risks 連結表(匯出改讀此表)
第 7 章稽核結果 result.attestations[] 一筆:parts[{name:'audit-conclusion', prose:全文}]、responsible-parties=稽核人員 ar_results.attestations JSONB
本次判定範圍 result.reviewed-controls.control-objective-selections[]=本次評估目標 part_id 清單 ar_results.reviewed_controls
第 1~6 章 從 AP 讀(FR-141) 不重存
控制項結論 無欄位,D5 即時推導 —

官方必填核對(v1.2.2 JSON schema):finding(uuid/title/description/target,target 再需 type/target-id/status)、observation(uuid/description/methods/collected)、risk(uuid/title/description/statement/status)、remediation(uuid/lifecycle/title/description)、result(uuid/title/description/start/reviewed-controls)、attestation(parts)——上表每一項都有來源,畫面不需多填。

%%{init: {'theme':'base','themeVariables':{'primaryColor':'#E2F0F1','primaryTextColor':'#14201F','primaryBorderColor':'#0E7C86','secondaryColor':'#EEF2F3','secondaryTextColor':'#14201F','tertiaryColor':'#FBFCFC','tertiaryTextColor':'#14201F','lineColor':'#4A5A5C','textColor':'#14201F','mainBkg':'#E2F0F1','nodeBorder':'#0E7C86','nodeTextColor':'#14201F','edgeLabelBackground':'#FBFCFC','titleColor':'#14201F','clusterBkg':'#FBFCFC','clusterBorder':'#E4EAEB','actorBkg':'#E2F0F1','actorTextColor':'#14201F','actorBorder':'#0E7C86','actorLineColor':'#C7D1D2','signalColor':'#4A5A5C','signalTextColor':'#14201F','labelBoxBkgColor':'#EEF2F3','labelBoxBorderColor':'#C7D1D2','labelTextColor':'#14201F','loopTextColor':'#14201F','noteBkgColor':'#F6EBD5','noteTextColor':'#14201F','noteBorderColor':'#9C6B12','activationBkgColor':'#EEF2F3','activationBorderColor':'#C7D1D2','sequenceNumberColor':'#FFFFFF'}}}%%
flowchart LR
    AO[評估目標頁<br/>佐證/其他佐證/稽核發現<br/>稽核結果/風險] --> F[finding<br/>target-id=part_id<br/>status.state / reason<br/>implementation-status]
    AO --> O1[observation 佐證<br/>EXAMINE<br/>relevant-evidence=檔案/連結/問卷]
    AO --> O2[observation 其他佐證<br/>methods 從稽核計畫帶<br/>description=文字]
    AO -->|判不符合且有填| K[risk<br/>characterizations.facets severity<br/>status=open]
    K --> M[remediation<br/>lifecycle=recommendation]
    F -.related-observations.-> O1
    F -.related-observations.-> O2
    F -.related-risks 連結表.-> K
    T[稽核報告頁籤第 7 章] --> A[result.attestations<br/>part name=audit-conclusion]
圖 2 — 一條評估目標存成哪些 OSCAL 物件

Excel 契約(填寫說明、計畫概要、評估目標、可選清單四頁,延伸 FR-141)

「評估目標」頁欄序:

欄 內容 規則
A(隱藏) part_id 比對鍵;不在本次稽核範圍的列略過
B~J 序號、控制項代碼、實務要求、執行說明、評估目標、查核方法與指引、受評人員、受評元件/資產、稽核人員 FR-141 計畫欄,灰底唯讀,匯入忽略
K 稽核結果 下拉:符合/不符合/不適用;空白=未判定;無效值預覽就地對應
L 佐證檔案 一行一個檔名,只含檔案;匯出列已採用者;匯入比對專案檔案,對不到預覽三選一
M 其他佐證 自由文字
N 稽核發現 不符合必填(匯入不擋,結案才擋)
O 風險等級 下拉:低/中/高;空白=無
P 風險說明 與 O 任一有值=有風險
Q 改善建議 → remediation

「可選清單」頁:稽核結果、風險等級、佐證檔案三欄(黃底),其餘沿用 FR-141。「計畫概要」頁唯讀、匯入不讀。範例:prototype/sample/FR-142-稽核結果範例.xlsx(產生腳本 make_sample_xlsx.py)。

匯入預覽(prototype/import-preview.html):同一畫面預覽模式;異動的評估目標標示、原值劃掉;無效值與找不到的檔名標「待確認」就地處理;對不到 part_id 的列略過;全部處理完才能匯入。

匯出三選一

GET /audit-round/<round_uid>/ar/export?format=docx|pdf|xlsx|zip&with_findings=true|false:

  • 稽核報告(Word/PDF):標題帶稽核次;第 1~6 章從 AP 帶;第 7 章=attestation 全文;附件依 D11。
  • 稽核結果工作表(Excel):上面四頁。
  • 全部檔案(ZIP):docx+xlsx。

§7

端到端流程

%%{init: {'theme':'base','themeVariables':{'primaryColor':'#E2F0F1','primaryTextColor':'#14201F','primaryBorderColor':'#0E7C86','secondaryColor':'#EEF2F3','secondaryTextColor':'#14201F','tertiaryColor':'#FBFCFC','tertiaryTextColor':'#14201F','lineColor':'#4A5A5C','textColor':'#14201F','mainBkg':'#E2F0F1','nodeBorder':'#0E7C86','nodeTextColor':'#14201F','edgeLabelBackground':'#FBFCFC','titleColor':'#14201F','clusterBkg':'#FBFCFC','clusterBorder':'#E4EAEB','actorBkg':'#E2F0F1','actorTextColor':'#14201F','actorBorder':'#0E7C86','actorLineColor':'#C7D1D2','signalColor':'#4A5A5C','signalTextColor':'#14201F','labelBoxBkgColor':'#EEF2F3','labelBoxBorderColor':'#C7D1D2','labelTextColor':'#14201F','loopTextColor':'#14201F','noteBkgColor':'#F6EBD5','noteTextColor':'#14201F','noteBorderColor':'#9C6B12','activationBkgColor':'#EEF2F3','activationBorderColor':'#C7D1D2','sequenceNumberColor':'#FFFFFF'}}}%%
sequenceDiagram
    participant U as 稽核人員
    participant FE as 稽核結果頁
    participant BE as BE ar_objective_app_service
    participant PKG as jedi-oscal-v2 AR services
    U->>FE: 進入稽核次(status=auditing)
    FE->>BE: GET /ar/objectives
    BE->>PKG: 讀 AP activities(AO 清單+方法)+ 既有 findings/observations/risks
    PKG-->>BE: 合成逐 AO 列(未判定=無 finding)
    BE-->>FE: AO 列+控制項結論(D5)+統計
    U->>FE: 逐條判定、填發現/佐證/風險/建議;或匯入 Excel
    FE->>BE: PUT /ar/objectives(整批)
    BE->>PKG: upsert finding(OSCAL 形狀)/observation/risk+remediation/連結表
    U->>FE: 稽核報告頁籤寫第 7 章(可帶入不符合事項)
    FE->>BE: PUT /ar/attestation
    U->>FE: 送出結案
    FE->>BE: POST /ar/finalize
    BE->>BE: 守門:未判定>0 或 不符合無發現 → 412
    BE->>PKG: finalize_assessment(有不符合→POA&M)
    U->>FE: 匯出報告 docx/pdf
    FE->>BE: GET /ar/export?format=docx
    BE-->>U: 1~6 章(AP)+7 章(attestation)+附件(findings)
圖 3 — 稽核次內從開始稽核到結案

§8

拆卡草案

第 0 棒已建卡(CM-2819)。第 1~6 棒在 design.md 定案後一次建完。排序以「決策者何時看得到畫面」為準,但棒 1 是資料形狀的地基必須先做。

棒 卡 做什麼 碰哪裡 套件 依賴 驗收
0 CM-2819 討論稿+雛形+Excel 範例 docs/features/FR-142…/ — — ✅ 定版
1 1a finding 改 OSCAL 形狀(target_status JSONB、新欄 implementation_status)、清 pending token、匯出改組;risk facets 陣列;匯出改讀連結表;remediation lifecycle NOT NULL+CHECK;migration pkg/jedi-oscal-v2 model/migration/ar_finding_matrix_service/oscal_io_service/assessment_risk_service jedi-oscal-v2 design 判一條不符合匯出 JSON 用官方 schema 驗過
1 1b observation、attestation service;新稽核次不預建 finding;D5 規則收斂進 aggregation.py 兩支套件 兩支 1a 新稽核次 finding 數=0,判定後=判過的評估目標數
2 2a ar_objective_app_service.py(新檔):讀取(合成列、候選佐證走 workflow_execution_control_mapping+job_evidences FILE/LINK/SURVEY、控制項結論、統計)、整批存、第 7 章、結案守門+鎖定+佐證凍結;route+schema app/flow_control/service/、api/project/routes/ — 1b Swagger 存三條讀回一致;未判定或第 7 章空白擋 412;結案後寫入 409
3 3a FE 新頁:左樹三層+燈號、控制項總覽、評估目標頁、稽核報告頁籤、報告預覽;路由改指;舊頁退役與舊稽核次唯讀 FE 新檔 — 2a 對照雛形逐頁操作
4 4a workbook 加 K~Q 結果欄;檔名比對;ar_workbook_export_service.py/ar_workbook_import_service.py;可選清單;FE 預覽模式 app/flow_control/service/、FE — 1b、3a 匯出改兩格與一個檔名匯回,預覽標出、確認後畫面更新
5 5a ar_report_template.docx(正文直式、附件分節橫式 8 欄)、ar_report_export_service.py、三選一 app/flow_control/service/、app/oscal/templates/ap/ — 2a Word 開看 1~7 章與橫式附件、判定中文
6 6a pass_scope_rule.py 讀評估目標層;稽核結果與風險等級選單 seed(system_menus)+i18n pkg/jedi-compliance-audit、scripts/sql/*-seed-*.sql jedi-compliance-audit 1b 第 2 次內稽新 AP 只剩不符合評估目標所屬控制項

§9

不做清單

像但不做 為什麼
POA&M 改版 POA&M 另開 FR 整個重做;本案只保證交接點(不符合評估目標的 finding、其 risk 與 remediation,均有固定 uuid)與過渡期「結案有不符合就生 POA&M」照樣能跑
舊稽核次資料遷移到評估目標層 D4
CRA 的「系統資料當證據」(風險評估、適用性等 evidence-source) CRA 另案調整為要求上傳文件;本案以 CMMC 為準
任務討論列為佐證 D8:只是溝通紀錄
連結、問卷在 Excel 關聯 D9:只在畫面設定
assessment-log(現場活動時間軸) 亞航報告沒有;observation 的 methods 已足
風險 deadline、risk-log、threat-ids、mitigating-factors 畫面沒欄位;留 NULL
AR 的 OSCAL JSON 匯出入口 套件已有 export_oscal AR 分支,本案只修它合規,不加前端按鈕
亞航原格式(無 part_id)xlsx 匯入改版 FR-044 parser 留作退路,不動

§10

坑與陷阱總表

# 坑 影響 對策
1 init_ar_matrix_for_round 現在預建 finding 且 target_id 存 control_id(2026-06-17 拍板) FR-140 縮範圍、FE 聚合、FR-044 匯入都假設「每控制項一筆」 1b 改 AO 層時 grep target_id 全部讀取者(pass_scope_rule、aggregation、ar_import、FE)一次改;D4 用 _obj. 判新舊
2 target_status JSONB 現存 {"product_state"},匯出直接吐 改形狀後舊資料匯出仍不合規 1a migration 把舊值轉成 {state, reason};舊 pending 列刪除(=未判定)
3 finding↔︎risk 連結表與 JSONB 不同步 匯出遺失關聯 1a 匯出改讀連結表,JSONB 欄停用(不刪)
4 assessment_result_app_service.py 860 行、RoundAuditReviewView.vue 1,083 行、ArImportDialog.vue 720 行皆超標 不能往裡加 2a/3a/4a 全部新開檔;舊檔只改一行導向或退役
5 「有風險」判準=風險等級或風險說明任一有值 只填改善建議 → 不算風險、控制項不會變不符合 填寫說明明寫;匯入預覽標「有改善建議但無風險等級」提醒(不擋)
6 「帶入不符合事項」接在現有內容後 按兩次內容重複 實作同雛形:接在後面,不覆蓋
7 OSCAL status.state 封閉值域;「不適用」要同時填 satisfied+reason=other+implementation-status 漏任一匯出不合規或報告印錯 1a 寫在 upsert 一個地方;驗收用官方 JSON schema 跑
8 報告附件欄多 直式放不下 D11:附件節橫式、欄數 8;取消「含稽核發現與風險」為 7 欄
9 同一支 audit_round_app_service.py 周邊 FR-140 卡與本案 6a 都要改 平行派互撞 6a 排在 FR-140 相關卡之後,母卡標序列組
10 finding description 官方必填,但符合時稽核人員常不寫發現 匯出不合 schema 存檔時空白自動補「經檢視佐證,符合本評估目標」,畫面不顯示這句
11 佐證候選清單要走 workflow_execution_control_mapping 權威 scope 同名檔案跨控制項被吸進來(FR-044 STG 實踩) 依 memory feedback_evidence_per_control_scope_wf_control_mapping:二次過濾 workflow_execution_id 真的對到該控制項;relevant-evidence 存字串 file_uid 不存數字 file_id
12 結案凍結佐證版本 受稽單位結案後換檔,稽核紀錄指向新檔 結案時把每筆採用佐證的 content_hash/版本寫進 relevant-evidence.props
13 Excel 檔名比對同名多筆 兩個任務交了同名檔案 預覽就地讓使用者選,不自動挑