手冊首頁 / 證據管理 / 證據分類誤判報表

證據分類誤判報表(Classification Adjudication Report)

功能群:證據管理|AI 分類生命週期、兩種「證據」區分、EC_ 錯誤碼、核心資料模型先讀 功能群總覽|姊妹頁:驗證報表(同一 run 的另一份下游報表,算「量化準確度」)

事實基準:2026-07-05 從 FE / BE code 掃出(FR-031);API 欄位逐條對照 adjudication_report_builder.py 組裝碼(本模組報表無 marshmallow serializer,route 直接回傳 builder dict,此 dict 即線上契約)。2026-07-06 自「證據分類報表」單頁拆分成 validation / adjudication 兩頁(各自對應獨立 FE route 與 view)。

變更紀錄:2026-07-09 FR-047 U-2 —— 報表載入失敗(404)補 FE error state(error ref + catch + v-else 錯誤畫面 + 重試 + i18n key),不再留純空白

1. 功能描述

誤判報表是 AI 證據分類 run 的唯讀下游報表,回答「這個檔案該不該放這裡、User 和 AI 誰對誰錯」:以固定的 CANON 正解基準(cmmc_l1_canon.json,程式碼內附資源檔,非資料庫表)同標準檢視 User 與 AI 的放置,找出 User 誤放、AI 多放、超出框架範圍的檔案。不寫入任何資料——每次開啟都即時運算,以 report_original(AI 首次輸出,immutable)與 state(覆核頁 User 修正後的 placements)分別對 CANON 判定(見 _overview §2)。

量化的召回率/精確率是姊妹頁驗證報表的職責,兩頁 Header 有互跳按鈕。

主要使用者:專案參與者(v1 實驗階段僅檢查 JWT 登入,未鎖角色,見 §3);用於盤點分類覆核成效、裁決 User 與 AI 的分歧。

角色速覽(完整定義與本群角色基調見 _overview §5;本頁 v1 為實驗階段檢視,未鎖角色):

角色 一句話
專案參與者 任何通過 JWT 登入且能存取此 run URL 的使用者,皆可檢視

1.1 功能總覽(本頁全部功能)

# 功能 說明 位置 詳述
1 Header:模型與門檻資訊 顯示本 run 使用的分類模型、confidence threshold Header §5
2 報表互跳按鈕 「查看驗證報表」+「返回覆核頁」導覽按鈕 Header §5
3 無 CANON 提示 available=false 時只顯示提示訊息,其餘區塊全部不顯示 頁面頂部 UC-ECR-02
4 判定基準圖例 說明 CANON 判定規則(放在 CANON 列出=對、放別的=錯、CANON 空集合=超範圍) 頁面頂部 §5
5 User 未審閱警示 note_user_equals_ai=true 時提示:本 run 尚未審閱,User 端等同 AI 端 頁面頂部 UC-ECR-02
6 User 標錯表 檔案 / User 誤放控制項 / CANON 正解 / AI 是否放對 / 理由;空清單顯示「(無)」 「一、User 標錯」 UC-ECR-02
7 AI 多放表 檔案 / AI 誤放控制項 / CANON 正解 / 理由;空清單顯示「(無)」 「二、AI 多放」 UC-ECR-02
8 超出框架範圍表 檔案 / User 放置 / AI 放置 / 理由(CANON 該檔為空集合,兩邊只要有放就列) 「三、超出範圍」 UC-ECR-02
9 逐 AO 比對明細(依控制項摺疊) <details> 巢狀:每控制項 has_issue 徽章(有放錯的預設展開),展開見每檔 User/AI verdict 著色 + 結論句 「四、逐 AO 明細」 UC-ECR-02

UC(§2)展開本頁具實質後端邏輯的路徑:誤判報表整體檢視(UC-ECR-02,含功能 3、5~9)。功能 1(Header 資訊)、2(互跳按鈕)、4(判定基準圖例)為純顯示/導覽,見 §5。正解基準匯入(UC-ECR-03)影響本頁「User 未審閱警示」的判定,規格見驗證報表 §6.3

2. Use Case

角色速覽(完整定義與本群角色基調見 _overview §5;本頁 v1 為實驗階段檢視,未鎖角色):

角色 一句話
專案參與者 任何通過 JWT 登入且能存取此 run URL 的使用者,皆可檢視

流程圖視覺慣例:菱形 = 判斷、橘底 = 例外/擋下、紅框 = 錯誤(標 error code)、綠框 = 成功終點、虛線 = 可選路徑。

UC-ECR-02 開啟誤判報表

項目 內容
角色 已登入使用者(無角色限制)
前置條件 run 已存在(DB 有列或 Drive 可回填);_state.json / _report-original.json 可讀取;另需 cmmc_l1_canon.json 資源檔存在才能產出完整內容
產出 / 後置條件 純讀取;CANON 缺檔時回傳 available=false 精簡殼,不視為錯誤(HTTP 200)
ecr_uc_02_adjudication start 使用者開啟誤判報表頁 (GET .../report/adjudication) check_run BE 檢查:run_folder_id 在 DB 有列或 Drive 可回填? start->check_run err_persist EC_RUN_NOT_PERSISTED (404,分類結果尚未保存) check_run->err_persist 回填後仍無法取得 run 實體 check_canon BE 判斷: cmmc_l1_canon.json 資源檔存在? check_run->check_canon 取得 run 實體 no_canon available=false (其餘欄位空陣列/預設值) check_canon->no_canon 缺檔 check_gt BE 判斷: 有匯入正解基準? check_canon->check_gt 存在 end_no_canon 回傳 200 report JSON (available=false,FE 顯示提示) no_canon->end_no_canon user_import User 側 = 匯入正解 check_gt->user_import check_reviewed BE 判斷: state 已審閱? check_gt->check_reviewed judge 逐檔:CANON 精確控制項比對 → user_wrong / ai_wrong / out_scope / undecided / by_control user_import->judge user_state User 側 = state placements note_user_equals_ai=false check_reviewed->user_state user_equals_ai User 側 = state placements note_user_equals_ai=true (比對意義有限) check_reviewed->user_equals_ai user_state->judge user_equals_ai->judge end_ok 回傳 200 report JSON (available=true) judge->end_ok
UC-ECR-02 流程:讀 run→CANON 資源檔存在?→否則 available=false 提早回傳→是則 User/AI vs CANON 逐檔判定→依控制項分組回傳

3. 權限矩陣

本群角色基調見 _overview §5。本頁實際檢查點:

操作 FE 判定 BE 強制 BE 檢查位置
開啟誤判報表 無(路由可直接進入) @jwt_required()無角色守門 api/evidence_classification/routes/evidence_classification_route.py::ClassificationRunAdjudicationReportRoute.get

⚠️ 已知不一致:報表 GET 專案角色(manager/auditor)檢查,僅要求登入——與觸發分類本身(鎖 manager,EC_NOT_MANAGER)不對稱。屬 v1 實驗階段已知邊界(見 _overview §7 坑 7),非資安定案,收斂鎖權限前不要假設此頁已受保護。

4. 狀態機與前置條件

本報表不受輪次 / AP 狀態機影響(無 assert_round_phase 或類似 phase guard);只要 run 存在即可檢視,即使專案已推進到後續階段。

條件 效果 出處
DB 無此 run_folder_id 且 Drive 也找不到 _state.json NotFound(EC_STATE_FILE_NOT_FOUND)(404) evidence_classification_service.py:997_ensure_run_persisted_for_read
DB / Drive 回填後仍拿不到 run 實體 NotFound(EC_RUN_NOT_PERSISTED)(404,EC_404008:「分類結果尚未保存,無法產生報表」) 同檔 :1094
cmmc_l1_canon.json 資源檔缺失 available=false,其餘欄位回空陣列/預設值(HTTP 200,非錯誤) adjudication_report_builder.py:30-33
無匯入正解 且未審閱 note_user_equals_ai=true(User 端等同 AI 端,比對意義有限) 同檔 :47-52

5. UI 設計

📸 實際畫面截圖待補(一律亮色模式拍攝):以 playwright 對 STG 擷取,預計補以下兩張到 assets/img/: ① 誤判報表整頁(Header + 判定基準圖例 + User 標錯/AI 多放表)ecr-adjudication-overview.png ② 誤判報表逐 AO 明細摺疊區塊(<details> 展開狀態,User/AI verdict 著色)ecr-adjudication-ao-detail.png

版面骨架與區塊職責(單欄長頁、無 tab、無 dialog,<details> 摺疊承載逐 AO 明細;彩色區塊可點跳本頁小節錨點,API 僅標代表性):

Header:分類模型/confidence threshold 互跳按鈕:查看驗證報表 / 返回覆核頁 跳至 §4 狀態機與前置條件(available=false 判定) 無 CANON 提示(available=false 時顯示,其餘區塊全部不渲染;HTTP 200 非錯誤)→ §4 跳至 §2 UC-ECR-02(開啟誤判報表) 判定基準圖例(放在 CANON 列出=對/放別的=錯/CANON 空集合=超範圍) + User 未審閱警示(note_user_equals_ai=true 時:User 端等同 AI 端) GET /classification-run/{run_folder_id}/report/adjudication(§6.2,本頁唯一載入) 跳至 §6 API 規格(user_wrong 欄位) 一、User 標錯表(檔案/User 誤放控制項/CANON 正解/AI 是否放對/理由) → §6.2 user_wrong[](空清單顯示「(無)」) 跳至 §6 API 規格(ai_wrong 欄位) 二、AI 多放表(檔案/AI 誤放控制項/CANON 正解/理由) → §6.2 ai_wrong[] 跳至 §6 API 規格(out_scope 欄位) 三、超出框架範圍表(CANON 該檔為空集合,User/AI 只要有放就列) → §6.2 out_scope[] 跳至 §6 API 規格(by_control 欄位與 verdict enum) 四、逐 AO 比對明細(依控制項 <details> 摺疊,has_issue 預設展開) 每檔 User/AI verdict 著色(correct 綠/wrong·out 紅/over 橘/undecided·none 灰)+結論句 → §6.2 by_control[] 彩色=可點跳本頁小節錨點|灰=本頁描述(Header/圖例/警示)|虛線框=條件顯示(無 CANON)/摺疊區 整頁單一 GET 載入;CANON 為程式碼內附資源檔(§9),與驗證報表的匯入正解是兩套機制(§12 坑 3)
誤判報表版面 wireframe:Header 互跳鈕、判定基準圖例與警示、User 標錯/AI 多放/超出範圍三表、逐 AO 比對明細

狀態呈現:共用元件 LoadingStatesize="page")顯示載入中;無 per-item spinner(一次性整頁載入)。verdict 用固定色碼(correct=綠、wrong/out=紅、over=橘、undecided/none=灰)。無 socket,一次性 onMounted 載入,無輪詢或手動重載按鈕。

6. API 規格

Envelope:成功 {"status": true, "data": …}、失敗 {"status": false, "data": "<錯誤訊息>"}common/util/response_util.py:4-16)。本模組無 marshmallow serializer——route 直接把 builder 回傳的 dict 交給 return_response,故下列欄位表即線上契約(來源是 builder 組裝碼,非 schema class)。

6.1 總清單(本頁呼叫的全部 endpoint)

分類 Method + Path 說明 完整規格
誤判報表 GET /classification-run/{run_folder_id}/report/adjudication 質化誰對誰錯報表(CANON 為準) §6.2

正解基準匯入 POST /classification-ground-truth(背景操作)影響本頁 note_user_equals_ai 判定,完整規格見驗證報表 §6.3

6.2 [GET] /classification-run/{run_folder_id}/report/adjudication

無 query 參數。Response data

欄位 型別 說明
available bool false = CANON 資源檔缺失,其餘欄位皆為空/預設值(FE 顯示「無 CANON」提示,不再渲染其他區塊)
run object available=true 時才有:{run_folder_id, model, confidence_threshold}
note_user_equals_ai bool true = 無匯入正解且 run 未審閱,User 端等同 AI 端(比對意義有限,FE 顯示警示)
user_wrong[] array {file, placed_control, placed_control_name, canon: [control_id...], ai_has_canon: bool, reason}——User 放置的控制項不在 CANON 內
ai_wrong[] array {file, placed_control, placed_control_name, canon: [control_id...], reason}——AI 放置的控制項不在 CANON 內
out_scope[] array {file, user: [control_id...], ai: [control_id...], reason}——CANON 判定該檔超出框架範圍(空集合)但雙方仍有放置
undecided[] array {file}——該檔不在 CANON 規則內,不判對錯
by_control[] array {control_id, control_name, has_issue: bool, aos: [{ao_id, ao_text, files: [{file, user_verdict, ai_verdict, canon: [control_id...], conclusion}]}]}

user_verdict / ai_verdict enum:correct(放對)/wrong(User 放錯,僅 User 側用此值)/over(AI 多放,僅 AI 側用此值)/out(超出範圍卻放了)/undecided(未裁定卻放了)/none(該 AO 未放)。

出處:app/evidence_classification/service/report/adjudication_report_builder.py:26-172build_adjudication_report)、evidence_classification_service.py:1089-1101get_adjudication_report@transaction);CANON 讀取 report_common.py:196-212load_canon,讀 app/evidence_classification/resources/cmmc_l1_canon.json)。錯誤:run 不存在 → NotFound(EC_RUN_NOT_PERSISTED)(404,EC_404008)。

7. 前端檔案地圖(compliance-manager-fe/)

檔案 角色
src/views/evidence-classification/EvidenceClassificationAdjudicationReport.vue 誤判報表主檢視(165 行)
src/config/router/index.js:870-875 route evidence-classification-report-adjudication,breadcrumb parent 為 evidence-classification-review
src/service/EvidenceClassificationService.js:56-59 getAdjudicationReport(),單參數 runFolderId 的 GET
src/config/api/api.js:397 端點常數 CLASSIFICATION_RUN_REPORT_ADJUDICATION
src/components/common/LoadingState.vue 整頁 loading 元件(size="page"
src/config/locales/i18n/{zh-tw,en}/evidence-classification.json 頁面 i18n,namespace evidence_classification.report.*

本頁無專屬子元件(verdict chip、表格皆為手刻 <div>/<span> + scoped CSS,非共用元件庫)。

8. 後端檔案地圖(本頁核心鏈路)

鏈路 Route App Service 底層
誤判報表 api/evidence_classification/routes/evidence_classification_route.py::ClassificationRunAdjudicationReportRoute app/evidence_classification/service/evidence_classification_service.py::get_adjudication_report@transaction report/adjudication_report_builder.py::build_adjudication_report + report_common.py::load_canon
run 讀取 / 惰性回填 同上共用 _ensure_run_persisted_for_read(DB 優先,缺列則從 Drive 三檔案回填並 upsert) ClassificationRunRepoImplself._run_ds)+ Drive 讀檔(self._drive_ops
匯入正解查詢(note_user_equals_ai 判定用) _load_ground_truth_aomap ClassificationGroundTruthRepoImplself._gt_ds

DDD 提醒:report route 遵守「route 不碰 DB、app service @transaction」的層級規範;唯一偏離常規之處是無角色檢查(見 §3 已知不一致),新增類似報表 API 時不要照抄「無角色守門」這點。

9. DB

9.1 資料表總清單(本頁讀寫的全部表)

讀/寫 說明 欄位詳述
compliance.evidence_classification_runs 讀(惰性回填時寫,見 §12 坑 2) 分類 run 記錄;report_original / state JSONB 是判定的兩側輸入 驗證報表 §9.3(欄位定義同源,不重複)
compliance.evidence_classification_ground_truth 匯入正解基準;有值時 note_user_equals_ai 不成立 同上

本頁的判定基準另讀檔案資源 app/evidence_classification/resources/cmmc_l1_canon.json(非資料庫表,程式碼隨版本內附的固定 CANON 規則檔,全租戶共用)。

9.2 ER 圖(本頁讀取範圍)

ecr_data_flow report_original report_original (AI 首次輸出,immutable) JSONB build_val build_validation_report() AI vs 正解基準 召回/精確/四級/未分類診斷 report_original->build_val AI placements (matches>=threshold) build_adj build_adjudication_report() User vs AI vs CANON 逐 AO 誰對誰錯 report_original->build_adj AI placements state state (User 審閱後 placements) JSONB state->build_val fallback 正解 (未匯入時) state->build_adj fallback User 正解 (未匯入時) ground_truth evidence_classification_ground_truth.mapping (匯入正解,per-tenant×framework) decision_gt BE 判斷:有匯入正解? ground_truth->decision_gt canon cmmc_l1_canon.json (固定 CANON 資源檔) decision_canon BE 判斷:CANON 資源檔存在? canon->decision_canon decision_gt->build_val 有 → gt_source=import (永遠 full) decision_gt->build_val 無 → gt_source=state (視審閱狀態) decision_gt->build_adj 有 → User 側用匯入正解 decision_gt->build_adj 無 → User 側用 state degraded mode=degraded (未審閱且無匯入正解,省略 summary) build_val->degraded 未審閱且無匯入正解 full mode=full (含 summary 召回/精確) build_val->full last_edited_at 或 archived_at 有值 或已匯入正解 no_canon available=false (FE 顯示「無 CANON」提示) build_adj->no_canon CANON 缺檔 available available=true (user_wrong/ai_wrong/out_scope/by_control) build_adj->available CANON 存在 decision_canon->build_adj 存在 → 才能判 user_wrong/ai_wrong
報表資料來源:run(藍,含兩個 JSONB 輸入)+ 匯入正解(綠)+ CANON 資源檔(虛線,本頁判定基準)→ builder 輸出報表 JSON

10. 頁面邏輯與資料對應

載入時序:單次載入,onMounted 直接呼叫 report API,無並行請求、無分階段渲染。

關鍵欄位對應(畫面 ↔︎ API):

畫面元素 FE state API 欄位
無 CANON 提示 !report.available available
User 未審閱警示 report.note_user_equals_ai 同名欄位
User 標錯 / AI 多放 / 超出範圍三表 report.user_wrong / .ai_wrong / .out_scope 同名欄位(皆空陣列時顯示「(無)」段落)
逐 AO 摺疊 verdict 著色 vCls(f.user_verdict) / vCls(f.ai_verdict) by_control[].aos[].files[].user_verdict/ai_verdict

儲存流程:無——本頁純讀取,無任何表單或儲存動作。

錯誤對應:BE 404(EC_STATE_FILE_NOT_FOUND / EC_RUN_NOT_PERSISTED)目前無 FE 專屬錯誤畫面——load() 只用 try/finally 控制 loading,沒有 catch 顯示錯誤訊息;若 API 拋錯,report 維持 null,畫面停在空白狀態,使用者只看到 Header 而無任何內容區塊(見 §12 坑 1)。

11. 背景行為與外部依賴

類型 內容
通知 本頁站內通知
背景 job 本頁不觸發任何 job;分類本身(觸發 / 容器執行)屬覆核前置頁的背景行為,見 _overview §2
Socket 本頁 socket / 輪詢;一次性載入,無重新整理機制(需重新整理瀏覽器才會重算)
jedi-* 套件 jedi-auth(JWT);報表運算本身是純 Python 邏輯(app/evidence_classification/service/report/),不依賴 jedi-oscal 等領域套件
系統參數 / 資源檔 app/evidence_classification/resources/cmmc_l1_canon.json(本頁 CANON 正解基準,隨程式碼版本內附,非資料庫、非可透過 UI 編輯)

12. 邊界情況與已知坑

  1. API 錯誤已有 FE 錯誤畫面(2026-07-08 FR-047 U-2):原本 load() 只有 try/finally、無 catch,run 不存在(404 EC_RUN_NOT_PERSISTED)或狀態檔遺失(404 EC_STATE_FILE_NOT_FOUND)時 report 保持 null、頁面留純空白(僅 Header 渲染)。已補 error ref + catch,模板加最終 v-else error state(含重試)+ 1 個 i18n key。注意這跟 available=false(HTTP 200,有明確「無 CANON」提示)是不同的空畫面
  2. _ensure_run_persisted_for_read 會惰性寫入 DB:本頁雖是「讀」頁,但若 run 尚未持久化(本期前的舊 run),BE 會從 Drive 回填三個檔案並 upsertevidence_classification_runs——屬一次性遷移行為,非常態
  3. 兩個「正解基準」概念不同源:本頁的 canon(程式碼內附資源檔 cmmc_l1_canon.json,全租戶共用固定規則,改動需改資源檔並隨版本部署)與驗證報表ground_truth(DB 表,per-tenant×framework 可透過 API 匯入覆寫)是兩套不同機制,不要混為一談
  4. CANON 判定是精確控制項比對,不看同家族user_wrong/ai_wrong 判斷是「放的控制項是否精確在 CANON 列出的集合內」,即使放到同一家族的相鄰控制項也算錯——比對邏輯比驗證報表的「AO選錯(已分到同控制項)」寬容度更嚴格,兩份報表對同一份錯誤分類可能給出不同嚴重度評價
  5. 無角色守門(v1 實驗階段):報表 GET 只檢查 JWT 登入,未限定專案角色(見 §3)
  6. 無重新整理機制:分類覆核頁修改 placements 後儲存進 _state.json(同步回 DB state 欄位),若使用者已開著本頁分頁,資料不會自動更新,需手動重新整理瀏覽器

13. 開發與驗證

  • 跑起來:BE python main_socketio.py(port 8000,log 在 log/app.log);FE 在 compliance-manager-fe/ 起 Vite dev server。BE 改 service / builder code 後必須重啟(無 hot reload)
  • 測試帳號:dev 環境一般登入帳號即可(無角色限制,密碼見 .env / 部署文件)
  • 導航路徑:登入 → 專案 → AP → 證據分類覆核頁 → Header 進入「查看誤判報表」
  • 前置資料:需已有一個分類 run(run_folder_id)且 DB 或 Drive 可讀到 _state.json / _report-original.json;若要看完整內容需確認 cmmc_l1_canon.json 資源檔存在於部署環境
  • E2Ecompliance-manager-test/ repo(Cucumber + Playwright);以 分類報表 / evidence-classification-report / adjudication 搜尋
  • 相關文件:FR-031(docs/features/FR-031-2605-evidence-classify-reports/,設計背景,非行為真相來源);覆核前置頁見 evidence-classification-review.md;姊妹頁驗證報表;DB / API 全量見 GAI-SD-02/03