本卡屬 FR-161(母卡見「母卡」欄),第 3 棒:讓事前資料真的出現在每個資源庫的程序書池裡。要改套件 jedi-compliance-audit(決策者 2026-10-23 已同意)。接在卡 2 之後。
客戶上傳的事前資料要自動出現在這家公司每個資源庫的「程序書池」裡,而且送審、存版、還原、複製資源庫的時候要跟著走。做法是:客戶每上傳一份資料,系統就在每個可以修改的資源庫程序書池裡各加一列。換新版就把那列的檔案換掉;刪除就把那列拿掉。顧問在某個資源庫點「這框架不用」,只把那個資源庫的那一列標記起來,其他資源庫不受影響。
四條複製路徑都只認程序書池列,控制項掛載也是掛在程序書池列上。若只在讀取時把事前資料併進畫面,這四條都要各補一套,漏一條就是稽核看不到或存版還原後消失:
送審凍結 套件 jedi_compliance_audit/app/service/audit_round_pass_app_service.py:122 _freeze_ssp
→ 主專案 app/oscal/service/ssp_document_pool_service.py:91 clone_pool_for_snapshot
→ 套件 jedi_compliance_audit/infra/repository/ssp_document_pool_query.py:78 clone_pool_docs
(逐列複製 file_id、description,沒有其他欄位)
存版/還原/複製資源庫
主專案 app/module_frame/service/ssp_snapshot_extras.py(106 行)
池內文件依 (file_id, description) 配對,再把掛載換成新 id
DEV 實查 oscal.ssp_reference_documents 欄位只有 id/uid/context_type/context_id/file_id/description+審計四欄,context_type='ssp' 共 57 列。ORM model 在套件 jedi_compliance_audit/infra/model/ssp_reference_document.py。
① 套件 jedi-compliance-audit(現版 1.4.0)
jedi_compliance_audit/migrations/005-ssp-reference-documents-pre-engagement.sql:ALTER TABLE oscal.ssp_reference_documents ADD COLUMN category_id BIGINT NULL, ADD COLUMN pre_engagement_file_id BIGINT NULL, ADD COLUMN is_excluded BOOLEAN NOT NULL DEFAULT false。不加 FK(compliance.pre_engagement_* 是主專案的表,套件不該認識它),加一般索引在 pre_engagement_file_id。SspReferenceDocument 加三個 mapped_column;clone_pool_docs 複製時帶上三欄;list_pool 回傳三欄。② 主專案切 path dependency:pyproject.toml 第 70 行 jedi-compliance-audit==1.4.0 先註解、第 124 行 path 形式取消註解,poetry update jedi-compliance-audit(一定要帶套件名,裸跑會升整棵樹)。這兩行改動不 commit;發版後由決策者裁示時還原 pin。
③ 主專案 ssp_snapshot_extras.py:存版、還原、複製資源庫配對池內文件後新建列時,帶上三欄。
④ 可寫資源庫清單:同步只改「可寫」的資源庫。不另寫判斷,從 common/authz/ssp.py 的 _guard_template_write(約 129~144 行)抽出「不檢查能力點的那半段」:resolve_template_owner → verify_template_writable → before_template_write,變成一支可重用的函式,守門與同步共用。⚠️ before_template_write(約 157 行)目前是空的,所以現在所有資源庫都算可寫;這是既有缺口(另有一張卡處理),本卡不補。動 common/authz/ 當次跑 ddd-compliance-reviewer。
⑤ 同步服務(新檔,例如 app/pre_engagement/service/pre_engagement_pool_sync_service.py),在卡 2 的各個 app service method 的同一個 @transaction 裡呼叫,透過 domain service 呼叫程序書池服務,不直接碰程序書池的 ORM:
新增資料 這家公司每個可寫資源庫的範本 SSP:程序書池各加一列
context_type='ssp', context_id=範本 SSP id, file_id=v1,
description=title, category_id, pre_engagement_file_id
上傳新版 可寫資源庫的對應列 file_id 換成新版(凍結 SSP、存版快照不動)
刪除 可寫資源庫的對應列刪除(連帶 _mappings)
標過時 可寫資源庫的對應列 is_excluded=true
搬大類 可寫資源庫的對應列 category_id 跟著改
新建資源庫/第一次開程序書池
補齊:這家公司所有未過時、此範本 SSP 還沒有列的事前資料各補一列
module_frames.template_ssp_id(tenant-scoped,RLS 會自動只看本租戶)。list_pool。兩處都只補缺的,重複呼叫不會多出列。⑥ 這框架不用:新增 PUT/DELETE /ssp/<ssp_uid>/document-pool/<doc_uid>/exclusion,走程序書池既有守門 require_manager(範本 SSP 會自動走資源庫守門)。只改那一列的 is_excluded。