本卡屬 FR-091(母卡 CM-1690)第三批,是三批裡最重的一張:九張表、5 條 route、22 個 entity 檔(19 個非 dataclass)、4 支 app service 直接 import
jedi_iam(套件間反向依賴,要改走 D8 identity port),且主專案接線在api/flow_control/__init__.py與 flow-engine 共用一檔、不在 CM-1689 的 11 支內——本卡 G 組把兩支一起收進 core/plugins/。與 flow-engine 卡(CM-17xx)不可並行派(flow-engine 卡改套件內部、本卡 G 組改主專案接線,主專案那檔只有本卡動,但兩張的驗收都要起 BE,錯開)。
jedi-compliance-audit(稽核輪次、POA&M、審閱、AP/AR 解析)套件側:plugin.py 236 行 6 dataclass;api/ 有 __init__.py(ctx 13 處)與 guard.py(license/project role/identity 三道守門)分兩檔;22 個 entity 只有 3 個 dataclass;logger 一半掛 common.jedi_compliance_audit 一半 __name__;48 處施工日誌。最要緊的:audit_round_app_service/poam_service/poam_app_service/review_service 四支直接 from jedi_iam.domain... import UserDomainService / UserQueryEntity 查暱稱——套件不准認識別的套件,這是 FR-069 D16 的違規,也是 STATE §2「compliance-audit 要開 identity port」的由來。主專案側:接線在 api/flow_control/__init__.py 的 create_module(),同時 register 本套件與 flow-engine、還混著 task-platform 的 task type 宣告,翻三個地方才看得懂這支接了什麼。
首腦核對(2026-09-13):plugin.py 236 行 6 dataclass;api/init.py 86 行(ctx 13)+guard.py(7 個函式);route 5;entity 檔 22(3 dataclass);表 project_audit_rounds/poams/review_marks/round_stage_transitions/round_rollback_supersessions/ap_docx_parse_jobs/ar_xlsx_parse_jobs/ssp_reference_documents/ssp_reference_document_mappings;migration 0(表由主專案建);tests 只 12 支(error code/URL/plugin 三支契約測試,沒有行為測試);harness 有 dev_app.py 無 compose 無 --smoke;施工日誌 48 處;jedi_iam 直接 import 6 處分布 4 檔;有吐 created_user_name(AP DTO、audit_round_app_service:171 手寫批次補名);tests/test_plugin_contract.py 無 PKG_ROOT(用別的寫法,runner 看它掃的範圍對不對)。主專案 49 檔 import(僅次於 flow-engine);venv 指工作樹。
套件:/Users/chouraymond/Projects/Jedicogy/module/jedi-python-package/jedi-compliance-audit/
app/service/audit_round_app_service.py:25,171-185(UserQueryEntity+手寫補名)
app/service/poam_service.py:9-10、poam_app_service.py:219、review_service.py:3(UserDomainService)
api/guard.py(三道守門要併進 guards.py 或留為 guards.py 的一部分,runner 判斷)
identity port 範例:jedi-iam CM-1686 commit 1668abb(plugin 開 identity 欄位+app/service/_audit_names.py fill_user_names);jedi-asset plugin/contract.py:83-84+app/service/_audit_names.py;D8 標準件 jedi-common/jedi_common/identity/context.py IdentityContext(resolve_user_names / resolve_user_ids)
SOP:extraction-sop.md §3.2(斷線四種手法)/§4.3/§5.1/§5.2;說明:plugin-anatomy.md「port 與 adapter」「主專案怎麼接」
主專案(本卡 G 組允許動的範圍):
api/flow_control/__init__.py → create_module() 裡 register 本套件與 flow-engine 的兩段搬去 core/plugins/,主專案自己的 flow_control route 留在原檔(那些是主專案的 route 不是套件的)
core/plugins/compliance_audit.py → 新建,三段:① identity 等 adapter ② build_adapters ③ mount
core/plugins/flow_engine.py → 新建,同形;ISettingsReader/INotifier 的主專案實作搬進 ① 段
core/plugins/__init__.py → PLUGINS 加兩列(位置:沿用原 blueprint 載入順序附近)
di_containers/(compliance_audit/flow_engine 相關)→ 只改 import 路徑,瘦身不做
test/test_module_boundaries.py → 守衛清單更新
現成範本:core/plugins/evidence_classification.py(CM-1700,同樣從 api/ 舊接法搬來)
plugin.py → plugin/ 五檔(無 migration);api/__init__.py+api/guard.py → guards.py(runtime()+三道守門的 lazy decorator,require_license 等對外名字不變)+routing.py。對外 import 一字不改,49 檔 AST 掃逐一實跑。PKG_ROOT 若有用 plugin 取的寫法一併改。__name__ 六處改 common.jedi_compliance_audit;四支 app service 拔掉 jedi_iam import——plugin/contract.py 的 Adapters 加 identity: Optional[Any] = None(D8 IdentityContext),build_services() 把它傳進四支 service,service 內改用 identity.resolve_user_names(login_names)(補暱稱)與 identity.resolve_user_ids(...)(若有拿 uid 換 id 的地方);audit_round_app_service:171 那段手寫批次補名改成 _audit_names.fill_user_names(dtos, identity)(照 jedi-asset/jedi-iam 各自那份,再複製第三份是已知債,jedi-common 收成共用件前先照抄,回寫註明)。identity 為 None 時暱稱回 None、不炸(降級行為與 asset 一致)。疆界守衛要能抓到:改完做突變——在任一 app service 加回 from jedi_iam... → test_plugin_contract.py 的「不 import 非白名單 jedi 套件」守衛要紅;若原守衛白名單裡放行了 jedi_iam,把它拿掉。inspect.signature 逐欄對照預設值;稽核輪次的狀態欄預設值錯了會讓專案狀態機走錯,這組要特別貼比對表進回寫。--smoke(test client 打一條 AP 列表 401/200,identity 用假 IdentityContext 回固定暱稱,斷言回傳 created_user_name 有值);pyproject.toml 加 addopts = "--import-mode=importlib";README 補新結構、identity port 接法、接線路徑。core/plugins/compliance_audit.py 與 core/plugins/flow_engine.py 各三段;api/flow_control/__init__.py 只留主專案自己的 flow_control route 掛載,兩支套件的 register 段搬走;identity 用 container.identity_container.identity()(與 asset 同一顆);PLUGINS 加兩列;守衛清單更新。adapters 內拿 DI 物件延遲解析。task-platform 的 task type 宣告若也在那檔,留原地不動(task-platform 是大卡)。tests/unittest/test_audit_names_identity.py):假 IdentityContext 回固定 map → 四支 service 回傳的 created_user_name 正確;identity=None → 回 None 不炸。tests/integration/test_service_behaviour.py(目錄新建,表用 Base.metadata.create_all;這支表多、外鍵指主專案表,conftest 照 jedi-system-core 自建最小宿主生態):建一輪稽核輪次→推進 stage→建一筆 POA&M→審閱標記,斷言狀態轉換與 RLS。urls_frozen.txt)。