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

證據分類驗證報表(Classification Validation Report)

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

事實基準:2026-07-05 從 FE / BE code 掃出(FR-031);API 欄位逐條對照 validation_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 的唯讀下游報表,回答「AI 分類量化準確度如何」:AO / 控制項層級的召回率與精確率、缺漏與多餘的四級嚴重度分類、未分類檔案診斷、Docker 容器執行紀錄、逐 AO 明細。不寫入任何資料、也不持久化「已確認」狀態——每次開啟都即時運算,以 report_original(AI 首次輸出,immutable)對照 state(覆核頁 User 修正後的 placements)計算差異(見 _overview §2)。

質化的「這個檔案該不該放這裡、User 和 AI 誰對誰錯」是姊妹頁誤判報表的職責,兩頁 Header 有互跳按鈕。

主要使用者:專案參與者(v1 實驗階段僅檢查 JWT 登入,未鎖角色,見 §3);用於 AI 分類品質評估。

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

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

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

# 功能 說明 位置 詳述
1 Header:模型與門檻資訊 顯示本 run 使用的分類模型、confidence threshold;DEV_MODE 時另顯示估算成本(USD) Header §5
2 報表互跳按鈕 「查看誤判報表」+「返回覆核頁」導覽按鈕 Header §5
3 degraded 模式警示 mode !== 'full' 時顯示警示:run 尚未審閱且無匯入正解,省略召回/精確 summary 頁面頂部 UC-ECR-01
4 整體準確度 4 張 KPI 卡 AO 層召回 / AO 層精確 / 控制項層召回 / 控制項層精確,各附命中數/總數 「一、整體準確度」 UC-ECR-01
5 缺漏/多餘四級分類表 缺漏 4 類(AI完全未分類/分到其他控制項/AO選錯/版本格式差異)、多餘 4 類(完全多餘/多到其他控制項/多到同控制項其他AO/版本格式差異)各附總數與 chip 「一、整體準確度」 UC-ECR-01
6 控制項層級表 逐控制項 User檔數/AI檔數/命中數/召回長條圖/缺漏數/多餘數 「二、控制項層級」 UC-ECR-01
7 AI 未分類診斷 pool/unplaced 計數 + A/B/C 三類卡(真正該補/格式已涵蓋/從未歸檔)+ 降門檻救回彙整 4 卡(ao/ctrl/none/zero)+ 三張明細表 「三、AI 未分類」 UC-ECR-01
8 Docker 容器執行紀錄 exit_code、處理數、已分類數、耗時、STDERR 有無、錯誤關鍵字(最多 20 行) 「Docker 執行 Log」 §6.2
9 逐 AO 明細(依控制項摺疊) <details> 巢狀:每控制項 n_diff/n_aos 徽章,展開見每 AO 相符/缺漏/多餘 chip list(有差異的控制項預設展開) 「五、逐 AO 明細」 UC-ECR-01

UC(§2)展開本頁所有具實質後端邏輯的路徑:驗證報表整體檢視(UC-ECR-01,含功能 3~9),以及唯一的寫入路徑——正解基準匯入(UC-ECR-03,見 §6.3;non-UI 背景操作,影響本報表的 gt_sourcemode)。功能 1(Header 資訊)、2(互跳按鈕)為純顯示/導覽,見 §5;功能 8(Docker 執行紀錄)是本報表回傳的一段區塊、隨 UC-ECR-01 一併運算,其欄位規格見 §6.2。

2. Use Case

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

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

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

UC-ECR-01 開啟驗證報表

項目 內容
角色 已登入使用者(無角色限制)
前置條件 run 已存在(DB 有列或 Drive 可回填);_state.json / _report-original.json 可讀取
產出 / 後置條件 純讀取,無寫入;即時運算回傳 JSON(不持久化任何「已確認」欄位)
ecr_uc_01_validation start 使用者開啟驗證報表頁 (GET .../report/validation) check_run BE 檢查:run_folder_id 在 DB 有列或 Drive 可回填? start->check_run err_state EC_STATE_FILE_NOT_FOUND (404,狀態檔不存在) check_run->err_state Drive 狀態檔也找不到 err_persist EC_RUN_NOT_PERSISTED (404,分類結果尚未保存) check_run->err_persist 回填後仍無法取得 run 實體 check_gt BE 判斷: 有匯入正解基準? check_run->check_gt 取得 run 實體 gt_import gt_source=import (永遠 mode=full) check_gt->gt_import check_reviewed BE 判斷: state 已審閱? (last_edited_at 或 archived_at 有值) check_gt->check_reviewed build 組裝:control_rows / unclassified / docker_log / ao_by_control (+ summary,非 degraded 時) gt_import->build mode_full gt_source=state mode=full check_reviewed->mode_full mode_degraded gt_source=state mode=degraded (省略 summary) check_reviewed->mode_degraded mode_full->build mode_degraded->build end_ok 回傳 200 report JSON build->end_ok
UC-ECR-01 流程:讀 run→依有無匯入正解決定 gt_source→有無審閱決定 full/degraded→組裝四類指標回傳

UC-ECR-03 匯入正解基準(ground-truth)

項目 內容
角色 已登入使用者(無角色限制,見 §3);目前無本頁 UI 入口,經 Swagger 或其他工具觸發
前置條件 mapping 為非空 dict({檔名: [ao_id, ...]});framework_id 省略時預設 cmmc-l1
產出 / 後置條件 evidence_classification_ground_truth per-tenant × framework upsert(唯一索引 uq_ecgt_tenant_fw);此後本報表對該 framework 優先採此正解(gt_source=import,強制 mode=full,見 §4)、誤判報表的「User 未審閱警示」判定也會參考;mapping 非 dict 或空 → EC_GROUND_TRUTH_INVALID(400)
ecr_uc_03_ground_truth_import start 匯入正解基準 (POST /classification-ground-truth) 非本頁 UI 觸發:Swagger/工具 auth BE:@jwt_required() (僅檢查登入,無角色守門) start->auth err_login 401 未登入 auth->err_login 未登入 chk_mapping BE 檢查: mapping 為 dict 且非空? auth->chk_mapping 已登入 err_invalid EC_GROUND_TRUTH_INVALID (400,mapping 非 dict 或空) chk_mapping->err_invalid upsert per-tenant × framework upsert evidence_classification_ground_truth (唯一索引 uq_ecgt_tenant_fw) chk_mapping->upsert count 展開 mapping: files=檔案數、placements=ao_id 總數 upsert->count end_ok 回傳 200 {framework_id, files, placements} count->end_ok effect 後續兩報表優先採此正解 gt_source=import,強制 mode=full (見 UC-ECR-01 / 02) end_ok->effect
UC-ECR-03 流程:POST ground-truth→僅檢查 JWT→驗證 mapping 為非空 dict(否則 400)→per-tenant×framework upsert→回傳計數;此後報表優先採此正解

3. 權限矩陣

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

操作 FE 判定 BE 強制 BE 檢查位置
開啟驗證報表 無(路由可直接進入) @jwt_required()無角色守門 api/evidence_classification/routes/evidence_classification_route.py::ClassificationRunValidationReportRoute.get
匯入正解基準(POST ground-truth,非本頁 UI 觸發) 無對應 FE 呼叫點 @jwt_required()無角色守門 同檔 ClassificationGroundTruthImportRoute.post

⚠️ 已知不一致:報表 GET 與正解匯入 API 皆專案角色(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:「分類結果尚未保存,無法產生報表」) 同檔 :1049
無匯入正解 且 state.metadatalast_edited_at/archived_at mode="degraded":省略 summary(無召回/精確數字) validation_report_builder.py:55
有匯入正解(evidence_classification_ground_truth 命中) 強制 mode="full"gt_source="import"),忽略是否已審閱 同檔 :47-51

5. UI 設計

📸 實際畫面截圖待補(一律亮色模式拍攝):以 playwright 對 STG 擷取,預計補以下兩張到 assets/img/: ① 驗證報表整頁(Header + 整體準確度 KPI 卡 + 缺漏/多餘表)ecr-validation-overview.png ② 驗證報表「AI 未分類」區塊(A/B/C 三類卡 + 降門檻救回彙整)ecr-validation-unclassified.png

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

Header:分類模型/confidence threshold(DEV_MODE 另顯示估算成本 USD) 互跳按鈕:查看誤判報表 / 返回覆核頁 跳至 §4 狀態機與前置條件(full / degraded 判定) degraded 模式警示(未審閱且無匯入正解時顯示,省略召回/精確 summary)→ §4 跳至 §2 UC-ECR-01(開啟驗證報表) 一、整體準確度:4 張 KPI 卡(AO/控制項 × 召回/精確,依數值套色) + 缺漏四級/多餘四級分類表(各附總數與 chip) GET /classification-run/{run_folder_id}/report/validation(§6.2,本頁唯一載入) 跳至 §6 API 規格(control_rows 欄位) 二、控制項層級表(User檔數/AI檔數/命中/召回長條圖/缺漏/多餘) → §6.2 control_rows[] 跳至 §6 API 規格(unclassified 欄位) 三、AI 未分類診斷:A/B/C 三類卡 + 降門檻救回彙整 4 卡 + 三張明細表 → §6.2 unclassified(catA 真正該補/catB 格式已涵蓋/catC 從未歸檔) 跳至 §6 API 規格(docker_log 欄位) Docker 容器執行紀錄(exit_code/處理數/耗時/錯誤關鍵字 ≤20 行) → §6.2 docker_log(log 檔不存在則整塊 null) 跳至 §6 API 規格(ao_by_control 欄位) 五、逐 AO 明細(依控制項 <details> 摺疊,n_diff>0 預設展開) 每 AO 相符/缺漏/多餘 chip list → §6.2 ao_by_control[] 彩色=可點跳本頁小節錨點|灰=本頁描述(Header/互跳按鈕)|虛線框=條件顯示(degraded 警示)/摺疊區 整頁單一 GET 載入;正解匯入 POST /classification-ground-truth 為背景操作(§6.3),非本頁 UI 觸發
驗證報表版面 wireframe:Header 互跳鈕、degraded 警示、整體準確度、控制項層級、AI 未分類診斷、Docker Log、逐 AO 明細

狀態呈現:共用元件 LoadingStatesize="page")顯示載入中;無 per-item spinner(一次性整頁載入,非漸進式)。KPI 卡依數值套色(kpiClass():≥70 綠 / ≥45 橘 / 其餘紅),控制項召回用色條(barColor() 同門檻)。無 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/validation 量化準確度報表(召回/精確/四級/未分類診斷/成本) §6.2
正解匯入(背景操作,非本頁 UI 觸發) POST /classification-ground-truth 匯入 {framework_id, mapping:{檔名:[ao_id]}, note?},per-tenant×framework upsert;目前 FE 無對應呼叫點 UC-ECR-03 / §6.3

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

無 query 參數。Response data

欄位 型別 說明
mode string full(可算召回/精確)/degraded(未審閱且無匯入正解,省略 summary)
gt_source string 正解基準來源:import(已匯入正解,優先)/state(fallback 用 User 審閱後 placements)
run object {run_folder_id, run_folder_name, model, confidence_threshold, triggered_at, completed_at, last_edited_at, archived_at}
cost object|null {input_tokens, output_tokens, cache_read_input_tokens, total_tokens, estimated_cost_usd};來源 report_original.metadata.token_usage,無則 null;FE 僅 DEV_MODE 顯示
summary object|null mode=degraded 時為 null;否則見下表
control_rows[] array {control_id, control_name, gt: int, ai: int, hit: int, miss: [file...], extra: [file...]}(逐控制項統計)
unclassified object 見下表
docker_log object|null {exit_code, processed, classified, elapsed, stderr, errors[], log_unclassified[], log_files[]};容器 log 檔不存在則 null
ao_by_control[] array {control_id, control_name, n_aos, n_diff, miss_total, extra_total, aos: [AO明細物件]}

summarymode=full 時)

子欄位 型別 說明
ao_level object {recall_strict, recall_soft, precision_strict, gt_total, ai_total, match, soft_match}(百分比或 null)
control_level object {recall, precision, hit, gt, ai, miss, extra}
missing object {total, unclassified, wrong_control, wrong_ao, version_format}(缺漏四級計數)
extra object {total, never, wrong_control, wrong_ao, version_format}(多餘四級計數)

unclassified

子欄位 型別 說明
pool_count int 未分類池檔案數
unplaced_count int 未放置檔案數
catA array A 類(真正該補),每項 {file, user_locations:[{ao_id}], candidates:[{ao_id, confidence}], recover:{type, text}}
catB array B 類(格式已涵蓋),每項 {file, ai_sibling, candidates}
catC array C 類(從未歸檔),每項 {file, candidates}
zero_files array 每項 {file, category, user_locations}
recover_summary object 降門檻救回彙整 {ao, ctrl, none, zero}
no_recover array catA 子集(無法救回者)

AO 明細物件ao_by_control[].aos[],陣列每項):

子欄位 型別 說明
control_id string 控制項 id
control_name string 控制項名稱
ao_id string AO id
ao_text string AO 文字
status string ✅完全一致/⚠️有差異/➖雙方皆無證據
gt array 正解檔案清單 [file...]
ai array AI 放置檔案清單 [file...]
match array 相符檔案清單 [file...]
missing array 缺漏,每項 {file, label}
extra array 多餘,每項 {file, label}

出處:app/evidence_classification/service/report/validation_report_builder.py:31-235build_validation_report)、app/evidence_classification/service/evidence_classification_service.py:1044-1056get_validation_report@transaction)。錯誤:run 不存在 → NotFound(EC_RUN_NOT_PERSISTED)(404,EC_404008)。

6.3 [POST] /classification-ground-truth(背景操作,非本頁 FE 觸發)

Request:

欄位 型別 必填 說明
framework_id string 預設 cmmc-l1
mapping object {檔名: [ao_id, ...]};非 dict 或空 → BadRequestError(EC_GROUND_TRUTH_INVALID)(400)
note string 備註

Response data

欄位 型別 說明
framework_id string 框架 id
files int mapping 檔案數
placements int 全部 ao_id 展開後總數

per-tenant×framework upsert(DB 唯一索引 uq_ecgt_tenant_fw on (tenant_id, framework_id))。出處:evidence_classification_service.py:1071-1087import_ground_truth@transaction)。目前 compliance-manager-fe/src/service/EvidenceClassificationService.js 無對應呼叫方法,此 API 尚無 FE UI 入口。

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

檔案 角色
src/views/evidence-classification/EvidenceClassificationValidationReport.vue 驗證報表主檢視(254 行)
src/config/router/index.js:864-869 route evidence-classification-report-validation,breadcrumb parent 為 evidence-classification-review
src/service/EvidenceClassificationService.js:51-54 getValidationReport(),單參數 runFolderId 的 GET
src/config/api/api.js:396 端點常數 CLASSIFICATION_RUN_REPORT_VALIDATION
src/components/common/LoadingState.vue 整頁 loading 元件(size="page"
src/config/featureFlags.js DEV_MODEVITE_DEV_MODE env)——成本欄位顯示開關
src/config/locales/i18n/{zh-tw,en}/evidence-classification.json 頁面 i18n,namespace evidence_classification.report.*

本頁無專屬子元件(KPI 卡、色條、chip 皆為手刻 <div>/<span> + scoped CSS,非共用元件庫),也無圖表函式庫(色條用純 CSS width + 動態背景色)。

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

鏈路 Route App Service 底層
驗證報表 api/evidence_classification/routes/evidence_classification_route.py::ClassificationRunValidationReportRoute app/evidence_classification/service/evidence_classification_service.py::get_validation_report@transaction report/validation_report_builder.py::build_validation_report + report/report_common.py(catalog / ai_placements / user_placements)
run 讀取 / 惰性回填 同上共用 _ensure_run_persisted_for_read(DB 優先,缺列則從 Drive 三檔案回填並 upsert) ClassificationRunRepoImplself._run_ds)+ Drive 讀檔(self._drive_ops
正解基準查詢 _load_ground_truth_aomap(讀 evidence_classification_ground_truth,轉 {ao_id:[file]} ClassificationGroundTruthRepoImplself._gt_ds
正解匯入(背景操作) 同檔 ClassificationGroundTruthImportRoute 同服務 import_ground_truth@transaction 同 repo upsert(),DB 唯一索引 uq_ecgt_tenant_fw

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 讀(UC-ECR-03 匯入時寫) 匯入正解基準(per-tenant × framework);有值時優先採用(gt_source=import §9.3

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

9.3 核心表欄位(取自 DEV DB dump,含 DB comment)

compliance.evidence_classification_runs — 證據分類 run 結果

欄位 型別 說明
run_folder_id varchar(128) Drive run folder id(自然鍵,唯一索引 uq_ecr_run_folder_id
tenant_id / project_id / project_uid / ap_uid / org_unit_id int / int / varchar(36) / varchar(36) / int 歸屬(ix_ecr_project_ap 索引 project_uid, ap_uidix_ecr_tenant 索引 tenant_id
framework_id varchar(64) 預設 cmmc-l1
model varchar(64) 分類所用模型名
confidence_threshold numeric(4,2) 分類信心門檻
status varchar(32) 預設 completed
archive_files boolean 預設 truetrue=完整歸檔模式、false=analyze-only(見 _overview §2
report_original jsonb AI 首次分類輸出(immutable)——報表比對的「AI 側」輸入
state jsonb 覆核頁讀寫的 placements 狀態(可能已被 User 修正)——報表比對的「User 側」預設輸入(無匯入正解時)
container_log text Docker 容器執行 log 原始文字,parse_container_log() 解析後供「Docker 執行紀錄」區塊
last_edited_at / archived_at timestamptz 決定 mode=fulldegraded 的關鍵欄位(皆空 = 未審閱)

compliance.evidence_classification_ground_truth — 證據分類正解基準

欄位 型別 說明
tenant_id integer 唯一索引 uq_ecgt_tenant_fw 的一部分(配 framework_id
framework_id varchar(64) 預設 cmmc-l1
mapping jsonb {檔名: [ao_id, ...]};builder 讀取時轉置為 {ao_id: [檔名, ...]}
source varchar(32) 記錄來源,如 import
note varchar(255) 匯入備註

10. 頁面邏輯與資料對應

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

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

畫面元素 FE state API 欄位
degraded 警示 !isFullreport.mode !== 'full' mode
4 張 KPI 卡 summary.ao_level.* / summary.control_level.* summary.ao_level.recall_strict/precision_strictsummary.control_level.recall/precision
缺漏/多餘四級 chip 直接綁 summary.missing.* / summary.extra.* 同名欄位
控制項層級表召回長條 barColor(c.hit/c.gt*100) computed control_rows[].hit.gt
AI 未分類三類卡 unc.catA/catB/catC unclassified.catA/catB/catC
Docker log 區塊 dockerLog(=report.docker_log docker_log.*
逐 AO 摺疊 report.ao_by_control 同名欄位,n_diff>0 觸發 <details open>

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

錯誤對應: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 等領域套件
系統參數 無 feature flag 控制報表本身是否顯示(DEV_MODE 只控制成本欄位)

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、頁面留純空白(全域 toast 3 秒後消失、無頁內提示、無重試)。已補 error ref + catch,模板加最終 v-else error state(含重試),並加 1 個 i18n key(zh-tw / en)
  2. _ensure_run_persisted_for_read 會惰性寫入 DB:本頁雖是「讀」頁,但若 run 尚未持久化(本期前的舊 run),BE 會從 Drive 回填三個檔案(_state.json / _report-original.json / container log)並 upsertevidence_classification_runs——這是本頁唯一會觸發寫入的路徑(正解匯入除外),屬一次性遷移行為,非常態
  3. 兩個「正解基準」概念不同源:本報表的 ground_truth(來自 DB 表,per-tenant×framework 可匯入覆寫)與誤判報表canon(程式碼內附資源檔,全租戶共用固定規則)是兩套不同機制——前者可透過 API 匯入變動、後者改動需改資源檔並隨版本部署
  4. mode=degraded 只省略 summary,不省略其餘區塊control_rows / unclassified / docker_log / ao_by_control 在 degraded 模式下仍會運算並回傳(因為它們用的是 AI vs state 的原始資料,不依賴 summary 的召回精確計算)——不要誤以為 degraded 等於整頁空白
  5. 正解匯入 API 目前無 FE 入口POST /classification-ground-truth 存在且可用,但 EvidenceClassificationService.js 未封裝呼叫方法,本頁也無匯入按鈕——目前只能透過 Swagger UI 或其他工具直接呼叫,日後若要在 FE 開放需另外規劃頁面/按鈕
  6. 無角色守門(v1 實驗階段):報表 GET 與正解匯入 POST 都只檢查 JWT 登入,未限定專案角色,與觸發分類本身鎖 manager 不對稱(見 §3)
  7. 無重新整理機制:分類覆核頁修改 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;若要看 mode=full 需先在覆核頁完成審閱(或已匯入正解)
  • E2Ecompliance-manager-test/ repo(Cucumber + Playwright);以 分類報表 / evidence-classification-report / validation 搜尋
  • 相關文件:FR-031(docs/features/FR-031-2605-evidence-classify-reports/,設計背景,非行為真相來源);覆核前置頁見 evidence-classification-review.md;姊妹頁誤判報表;DB / API 全量見 GAI-SD-02/03