建議 model:opus/effort:medium — 新表+新守門軸(要加平台管理員插座)+解析鏈有四層退路,邏輯錯了會靜默用到錯的設定。

本卡屬 FR-107(母卡 CM-1843)第 .5 棒(子需求卡 CM-1848),子任務 T-5.1:開一張表存「AI 要扮演什麼角色、怎麼判斷」的設定,並做出維護它的 API。

這張卡做什麼(白話)

現在 AI 分類的指令是寫死在容器程式裡的:「你是 CMMC 2.0 Level 1 評估專家」。換一個合規框架就完全不能用。

這張卡開一張表 classification_profiles 把這些設定搬出來,讓它可以針對不同的框架版本各設一份:

解析有四層退路,所以不建任何設定也能跑:先找「這個租戶+這個框架版本」→「出廠通用+這個框架版本」→「這個租戶的通用設定」→「出廠通用設定」→ 都沒有就用程式內建的最小版(不含任何框架名)。

守門:只給平台管理員(裁示 4)。套件現在只有「專案角色」的守門插座,要新加一支平台管理員插座 IPlatformAdminGuard。

動哪些檔/表

套件(走 path dependency 開發)
~/Projects/Jedicogy/module/jedi-python-package/jedi-evidence-classification/
  .../infra/model/classification_profile_model.py     ← 新增
  .../domain/entity/ + repo interface + impl
  .../app/service/classification_profile_service.py   ← 新增,resolve()
  .../domain/ports.py  ← 加 IPlatformAdminGuard(套件現在只有 IProjectRoleGuard)
  .../api/routing.py   ← 加四支 CRUD route
  .../  BUILTIN_MINIMAL 常數(🔴 不含任何框架名)

主專案
scripts/sql/packages/jedi_evidence_classification/00N-classification-profiles.sql
    ← 新增:表 + RLS + GRANT + sequence + ROOT 通用 seed 一筆
core/plugins/evidence_classification.py  ← 加 IPlatformAdminGuard 的宿主 adapter
    (委派 common/authz/ 的平台管理員軸,🔴 不要另寫一套)
di_containers/  同步注入

表結構:compliance.classification_profiles(design.md §6.1.5)

欄位                          型別                 說明
id / uid                     慣例
tenant_id / org_unit_id      int NOT NULL         租戶自己的設定;ROOT 那筆是出廠通用設定
framework_version_id         int NULL             🔴 軟參照 oscal.framework_versions.id
                                                   (另一支插件的表,不建 FK)
                                                   NULL=通用
name                         varchar(128) NOT NULL 顯示名
persona                      text NOT NULL        AI 角色
                                                   例「你是 CMMC 2.0 Level 1 評估專家」
guidance                     text NULL            分類指引(怎麼判、什麼算證據)
evidence_hints               JSONB NULL           依 part_id 或 group_id 給的提示
                                                   {"AC.L1-3.1.1_obj.2": ["帳號清單","AD 截圖"]}
model_default                varchar(64)          批次沒指定時用
confidence_threshold_default numeric(4,2)         同上
enable                       bool DEFAULT true    關掉就退到下一層
慣例四欄

UNIQUE (tenant_id, framework_version_id)   每租戶每框架版本一筆,NULL 視為通用那筆
RLS 四條 policy + GRANT TO cm_app + sequence 權限

🔴 為什麼放 compliance schema 而不是 oscal:
   表由 jedi-evidence-classification 套件擁有,schema 跟著擁有者走;
   與 framework_versions 的關聯是軟參照(裁示 3)。

解析順序(design.md §6.5,逐字照做)

for fv_id in context.framework_version_chain(project_id):   # 專案指定 → living SSP → catalog
    p = profiles.find(tenant_id, fv_id, enable=True) or profiles.find(ROOT, fv_id, enable=True)
    if p: return p
p = profiles.find(tenant_id, None, enable=True) or profiles.find(ROOT, None, enable=True)  # 通用
return p or BUILTIN_MINIMAL

BUILTIN_MINIMAL(程式內建,🔴 不含任何框架名)
  persona:  "You are a compliance assessment expert. Classify each evidence file
             against the assessment objectives listed below."
  guidance: 通用判準三句(證據要能直接證明該檢查點;一檔可對多項;不確定就低信心)

framework_version_chain 走 T-2.1 定的 IClassificationContext 插座(T-2.2 已實作)。

API(design.md §6.6 最後一列)

GET    /api/1.0/classification-profiles            平台管理員
POST   /api/1.0/classification-profiles            平台管理員
PUT    /api/1.0/classification-profiles/<uid>      平台管理員
DELETE /api/1.0/classification-profiles/<uid>      平台管理員

守門軸:與「框架版本管理頁」同一個軸(平台管理員)
🔴 主體域守門(只看「你是誰」)允許做成 route decorator,
   但 decorator 內部要委派 DI 注入的 guard service,route 本身不碰 session。
   套件內走新加的 IPlatformAdminGuard,宿主 adapter 委派 common/authz/。