FR-069 主專案功能模組化——jedi-* 套件抽取計畫 — 設計文件

狀態:第一階段執行中(P0 進行中)|建立日期:2026-08-29 討論脈絡:本案無獨立討論稿——盤點(三棒平行探勘)與拍板均在對話中完成,決策脈絡完整收錄於本文件 §3 決策定案表。

變更紀錄

日期 變更 對應
2026-08-31 D17/D18 拍板入決策表(第四階段地基棒 CM-1475)——D17 資料關聯三律(想建外鍵=該合併疆界/真跨疆界=軟參照存 id 不建約束/流程耦合=事件;外鍵塞不進 port,故疆界切分在資料層另立判準)、D18 設定 schema 申報制(schema 進套件、值與存放留宿主、模組開關表永遠留宿主;含作用域必填/預設活在 code DB 只存差異/fallback 鏈由套件申報三補充)。§7 第四階段節改寫為定序棒次表(4.A→4.B→P12→flow_control→P13→P9/P10→P11→P6,每棒附排序理由);架構手冊新增 package-taxonomy.md 套件分類地圖(十族) 母案 / CM-1475
2026-08-30 改名棒 CM-1464 執行完畢——monorepo jedi-identity/jedi-iam/(import 名 jedi_iam)、三支轉發殼轉發目標同步、主專案 96 處 import 改名;jedi_identity 不留轉發殼(未上 Nexus、無外部消費者),守衛測試加擋舊名復活;§3 D9 與 §7 2.5 節同步改名 CM-1464
2026-08-30 flow_control 拆出由終局選項升格為第四階段議程(user 指示;與 P13 同席設計,D12 單向依賴耦合);終局選項縮為 project 平台化一項 母案
2026-08-30 D9 命名修訂:PM 拍板 jedi-identity→jedi-iam(CM-1464 執行);D12 前置查證完成(CM-1462,改寫方向待裁);§8 圖表同步改名 母案 / CM-1462 / CM-1464
2026-08-30 新增 §8「套件階層依賴圖」(living)——三層架構圖+port 接線圖+逐套件狀態表(維護主體);原端到端驗收改列 §9。此節隨每次拍板同步更新 母案
2026-08-30 D13 追加:jedi-department/jedi-resource-store 即刻退役執行(user 拍板、首腦四面查證零使用)——主專案拔 pin 清殘行、monorepo 兩包標 deprecated;§8.3 兩列改「已退役」 母案 / CM-1435
2026-08-29 初版定案:P0–P8 第一階段收案(P6 ai-dashboard 降觀望)、P9–P13 凍結進路線圖、authz 拆兩半併 jedi-auth、抽取配方沿用 jedi-information-system 範本 母案
2026-08-29 D5 拍板——grc 模組改名 flow_control,納入 P0 範圍(P0-⑤) 母案 / CM-1436
2026-08-29 P0 實作已由平行 session 開工(working tree 現況:uploadfile 合併+error code 歸位進行中)。P0-⑤ 改名(D5)為後拍板追加,該棒需讀 CM-1436 卡的範圍追加補做 CM-1436
2026-08-29 D6 拍板——目標升級為「插件(plugin)模式」:套件自帶 api 層 / DI container / migration,隨插即用;驗收核心=拔掉測試。P1 負責定義插件契約首例,P2–P5 照抄 母案 / CM-1437
2026-08-29 D7 拍板——複用保障三件套:standalone harness+接入 README 為每支套件標配(P1 首做入 SOP);插件 vs 服務化形態分流準則入凍結路線圖 母案 / CM-1437
2026-08-30 D8 拍板——全路線解凍(廢除「有第二個消費者才抽」原則,P6+P9–P13 全解凍)+新增第二階段(ext 表收斂+JSONB 擴充容器)與第三階段(既有 20 支老套件升級插件模式)+插件契約補「身分脈絡標準件」(user/tenant/org_unit 名冊 port 一族)。§7 由「凍結路線圖」改寫為「第二~四階段與終局選項」 母案 / CM-1435
2026-08-30 D9 拍板——身分族合併為 jedi-identity(auth+login+mfa+captcha 四合一+主專案身分性質中介層收進套件),插隊為第 2.5 階段(第二階段表收斂後、第三階段補殼前);notification 維持獨立、agent 機器身分不併;順手清理四項(jedi-department 下架等)。另立 RLS 覆蓋缺口獨立 case(user_roles/user_tenants/user_org_units 三表無 RLS),不混入本案 母案 / CM-1435
2026-08-30 疆界盤點案(FR-069.9)——第四階段開工前置:照 jedi-identity 案的方法對全套件庫(26 支+主專案候選模組)做疆界地圖,定出合併/獨立補殼/退役/下架的完整去向,供拍板後改寫第三、四階段棒次表。與第二階段平行(純分析不動碼)。順手:D9 前置條件改「已確認」(user 確認 jedi-* 僅 Guidant AI 消費) 母案 / CM-1435
2026-08-30 D10–D16 批次拍板——疆界地圖(boundary-map.md)與 ext 盤點(phase2-ext-table-inventory.md)裁決落地:問卷疆界合併成立(P11 改寫)、device 不併檢測(P9 改寫)、OSCAL 三角第三邊改 flow_control(P13 開工前先查證)、三支退役先標 deprecated、bulletin 維持獨立套件、CM-1449 首批改打 project_extensions、基礎依賴 port 化通則入插件契約。⚠️ 編號註記:boundary-map §6 自用的 D15(jedi-project 凍結)/ D16(jedi-issue 死碼去留)尚未拍板,本表 D15/D16 依決策表 canonical 重新編定,地圖那兩項改列「待另議」 母案 / CM-1446 / CM-1447

1. 需求背景與目標

主專案(compliance-manager-be)歷經多輪功能開發,累積約 40 個註冊模組、1500+ 個 py 檔,多數功能未模組化——所有能力都長在主專案內,未來其他產品要複用相同功能(遠端 agent、授權驗證、防篡改、log 轉發…)時無法直接轉移套用。本案目標:把可通用的功能抽成 jedi- 外部套件*,放進既有 monorepo(~/Projects/Jedicogy/module/jedi-python-package/,已有 20 個套件),未來新產品以 poetry 依賴直接安裝複用。

盤點關鍵事實(2026-08-29 三棒平行探勘結論)

  • 核心不可分割環participant ↔︎ flow_engine ↔︎ grc ↔︎ associations ↔︎ oscal ↔︎ module_frame 六模組互相雙向引用、直接穿透 ORM model,合計約 760 檔(超過全專案一半)——這一團是產品本體,第一階段不切片。
  • 外圍有一圈乾淨的葉節點:約 8 個模組零跨模組依賴、只吃 common/ + jedi_common,是低風險抽取候選。
  • common/ 不能整包搬:需三分——真橫切的進 jedi-common、授權語意的進 jedi-auth、業務語意的歸位回各模組。且 common/ 現有 9 條反向 import 上層(違反分層方向),是搬遷前的硬前置。
  • 抽取先例已存在:jedi-information-system(FR-032 G)是從主專案抽出的成功範本——import 名不變、IUserLookup 窄介面解耦、套件不含 api 層、守衛測試防回歸。本案全程沿用該配方。
  • 依賴方向的關鍵洞見:模組能不能抽,看的是它「往外依賴多少」(out-degree),不是「被多少人依賴」(in-degree)——import 名不變,消費端不用改任何一行。此洞見決定了凍結路線圖中 participant 的定位(最大 hub 卻最先能抽)。

2. 分工概述(30 秒版)

整案一句話:先清理地基(P0),再把六支零耦合的基礎設施模組抽成新 jedi 套件(P1–P5),最後把 common/ 的橫切能力上移進 jedi-common 與 jedi-auth(P7–P8);核心業務模組的抽取凍結成路線圖,等這一輪做完拿實際成本數據再議。

階段 做什麼 產出 完成怎麼判定(決策者檢查法)
P0 前置清理 合併重複的上傳模組、斷 common/ 的 9 條反向引用、錯放的錯誤碼歸位 乾淨的主專案地基(不產新套件) 請 Claude 跑 `grep -rE "from (domain
P1 jedi-ai-bot 把 AI 聊天機器人抽成套件(最小、練手走通整條流程) 新套件上 Nexus + 主專案 pin poetry show jedi-ai-bot 看得到版號;系統內 AI 聊天功能手測正常
P2 jedi-integrity 防篡改偵測(FR-064 成果)抽成套件 新套件 + pin 同上檢查法;落地版啟動防篡改 gate 手測正常
P3 jedi-log-forwarding Log 轉發(FR-068 成果)抽成套件 新套件 + pin 同上;UI 設定轉發到測試 syslog 收得到 log
P4 jedi-remote-agent 遠端 agent 註冊/心跳/派工(mTLS+JWT)抽成套件 新套件 + pin 同上;agent 心跳與檢測派工手測正常
P5 jedi-license-runtime 授權驗證/機器指紋/到期狀態機抽成套件 新套件 + pin 同上;換一顆 license 檔啟用流程手測正常
P7 jedi-common 擴充 全專案最熱的通用工具(回應包裝等)上移進 jedi-common jedi-common 新版 poetry show jedi-common 版號有進;請 Claude 跑既有測試全綠 + 抽測三個常用頁面 API 回應格式不變
P8 authz 併 jedi-auth 授權守門「主體域」半包併入 jedi-auth jedi-auth 新版 同上;用 admin / 一般帳號各登一次,權限行為與改前一致

依賴一句:P0 是 P7/P8 的硬前置;P1–P5 彼此獨立可平行派工;每支套件抽完都要等發版上 Nexus 才能 commit 主專案的目錄移除。決策者功課:每階段收口時做上表「檢查法」欄的手測。


3. 決策定案(D1–D18)

# 決策 定案
D1 第一階段範圍 收 P0–P5 + P7–P8 共 8 個 arc。P6 jedi-ai-dashboard 降到觀望梯隊——AI 儀表板生成引擎概念上通用,但資料源 registry 深綁本產品 data API,port 化成本不小,且目前無第二個產品確定要此能力;按「沒消費者不抽」原則不過線。P5 jedi-license-runtime 收案——License Center 已是獨立系統、落地版產品線是既定方向,消費者可預期,複用價值最明確。
D2 核心模組(P9–P13)處置 凍結進路線圖(§7),不排時程。理由:①抽取收益只在「有第二個消費者」時兌現,目前無具體產品在等;②P0–P8 做完會拿到「抽一支套件實際花幾棒、踩什麼坑」的可信成本數據,屆時評估 5–10 倍工程量的核心抽取才有依據;③凍結不是丟掉——P0 清理與守衛測試會讓核心環邊界持續變乾淨,前置成本已被順手支付一部分。例外:若近期出現要用檢測能力的新產品,P9(jedi-detection)可單獨解凍提前。
D3 authz 去向 拆兩半:主體域(platform.py / admin.py / capability.py / decorators.py / signed_token.py——只看「你是誰」)併入 jedi-auth;資源域(project.py / ssp.py / workflow.py / menu_license_filter.py——要先 resolve 資源才知道判誰,帶產品語意)留主專案。被排除方案=獨立 jedi-authz:會立刻新增一條 jedi-auth 依賴邊(monorepo 第 5 條非 common 邊)、強迫消費者永遠裝兩包對版本,且不存在「只要 authz 不要 auth」的消費場景。附帶收益:9 條反向 import 中指向 domain.oscal / domain.participant 的 5 條全在資源域那半,拆半後 P8 的搬遷面自動避開它們。
D4 抽取標準配方 全程沿用 jedi-information-system(FR-032 G)範本:①dist 名連字號、import 名底線,消費端 import 句一字不改;②跨套件耦合一律 dependency inversion——套件內定義窄 ABC port(如 IUserLookup / INotifier),主專案寫 adapter + DI 注入;③套件只到 app service 層——route、DI container、DB migration 留主專案(套件只 ship ORM model);④extract → publish → pin 是綁定順序——主專案「移除目錄 + pin」的 commit 必須等套件推上 Nexus 之後;⑤每支套件寫一支守衛測試(grep 套件源碼 0 處主專案 import),比照 test/test_fr032g_information_system_decouple.py
D5 grc 模組改名 grc 改名 flow_control(流程控管),納入 P0 範圍(P0-⑤)。改的範圍=python 目錄與類名:app/grc/app/flow_control/domain/grc/infra/grc/api/grc/ 同步,DI 註冊(containers.py / app_modules.py)跟改,GrcErrorCodeFlowControlErrorCode 等類名跟改。不改=error code 字串值(GRC_404001 等——wire 契約,FE error-code.json i18n 靠字串比對)、對外 API URL path、DB 內容。理由:GRC(治理/風險/法遵)名大於實——模組實際是「流程節點掛業務(頁面/功能/狀態)」的流程控管層,稽核只是第一個掛進來的業務,未來問卷填寫審核等流程都會套此模式;與 flow_engine 成對命名(引擎推流程、控管掛業務);業界對應概念為 case management / process orchestration 的應用層。被排除方案:audit(綁死稽核語意,與通用化願景衝突)、engagement(稽核/顧問業行話,對通用流程不直覺)、process_control(撞工業控制語感)、case_management(case 一詞內部已被 Notion 任務卡佔用)。
D6 插件契約(plugin contract) 抽取目標從 library 升級為 plugin——隨插即用。每支新套件自帶完整垂直切片:①api 層(Flask blueprint / resources)②預設 DI container ③migration 腳本(隨包 package data,安裝時套用)④標準註冊入口(register(app, adapters) 形式,具體簽名由 P1 定案;簽名需預留四類插槽——config(參數值差異)/ adapters(行為差異)/ schema_extensions(欄位差異)/ mount_api(端點卸載逃生門),詳細指引見 CM-1437 卡「API 差異化四道防線」段;此為 D6 實作細節,不另立決策)。主專案接觸面收斂為:config/app_modules.py 一行註冊 + port adapter 實作。驗收核心=拔掉測試:註解掉註冊行後 BE 正常啟動、該模組選單/路由消失、其餘功能不受影響。邊界誠實聲明:做到 install-time pluggable(安裝時可插拔),非 runtime 熱插拔——DB schema / RLS 不可能執行中掛載,對齊業界(GitLab / Odoo 模組)等級。與現行慣例的關係:刻意偏離既有 jedi-* 慣例(套件無 api 層、route 留主專案,即 D4-③)——新契約自 P1 起適用於 FR-069 新抽套件,既有 20 支套件不回頭改;D4 其餘各項(import 名不變、port 解耦、extract→publish→pin、守衛測試)照舊適用。地基盤點:app_modules.py 本就是模組註冊表(fail-fast 載入)、選單走 DB ui_routes、license gating 機制已在——半成品地基可承接。
D7 複用保障三件套 防「開發完一包就沒了」的三條標配。① standalone harness(每支新套件標配):套件自帶最小獨立宿主——dev_app.py(最小 Flask app)+ docker-compose(起獨立 DB)+套件內測試可脫離主專案獨立跑,並由 CI 獨立執行。動機:「模組能離開宿主活著」是業界判斷真解耦的黃金標準——harness 跑得起來就是零隱藏耦合的鐵證(比 grep 守衛強一級);且 CI 天天跑讓套件有自己的生命跡象,主產品改動導致套件壞掉會當天被抓到,而不是等下個產品要用時才發現屍體。② 接入 README(每支新套件標配):「新產品如何接入」文件——要實作的 port 清單、註冊行寫法、migration 套法、10 分鐘 quickstart。動機:第二個產品團隊評估「讀懂套件 vs 自己重寫」時,沒這份必選重寫(業界 library 複用最常見死因)。③ 形態分流準則(入凍結路線圖 §7,非本階段執行項):P9 之後每支候選啟動前先判——有獨立生命週期的能力(如未來檢測平台)評估走服務化(License Center 模式:獨立部署、網路 API、自有 DB,邊界是網路協定想耦合都耦合不了);與宿主同進退的能力走插件(D6 契約)。理由背景:業界 rule of three——沒有兩三個真實消費者前,抽出的東西只是搬了位置的產品程式碼;①②就是在消費者出現前維持套件可信度的機制。
D8 全案解凍與階段重整(2026-08-30) 廢除「有第二個消費者才抽」原則——動機重新定調為「把歷史發散、耦合過高的能力一次整併成可抽換式,安裝即有 API 可用」,此目標本身即成立,不等客戶。P6(AI 儀表板)與 P9–P13 全部解凍。全案階段結構重整(詳見 §7):第一階段=P0–P8(原範圍,收尾中);第二階段=ext 表收斂+JSONB 擴充容器(純展示型客製欄位收回主表+容器、帶業務邏輯欄位轉正式欄位、auth/user 優先、ext 表模式收斂後退役)+ jedi-common 查詢層補能力(JSONB 擴充欄位查詢/過濾+「身分脈絡包」共通定義);第三階段=既有 20 支老套件升級插件模式——每支補:自帶 api 層、register 四插槽、harness、接入 README、拔掉測試、(有表的)migration 隨包、(有吐稽核欄位的)身分脈絡名冊。分級處理:完整升級(auth / file-upload / notification / survey / flow-engine 等多消費者)/輕量升級(captcha / bulletin / system-menu 等小而穩)/評估退役或合併(盤點時現形者)。jedi-auth 排首棒示範——P8 動完邊界、第二階段動完表、此階段補殼=新標準完全體;第四階段=原凍結區全解凍(P6、P9、P10、P11、P12〔人員指派,解耦鑰匙,本階段先做〕、P13〔OSCAL 三角,P12 之後〕),內部順序於第一階段總結時定;終局選項=flow_control / 專案本體平台化,唯一保留「等商業決策」。三案交錯原則:jedi-auth 被 P8(邊界)→ 第二階段(表)→ 第三階段(殼)各動一個面向,依此順序不互踩。
D9 jedi-iam 身分套件合併案(2026-08-30) jedi-auth+jedi-login+jedi-mfa+jedi-captcha(降級為 turnstile 小模組)合併為 jedi-iam;jedi-notification 維持獨立(12 個消費點多與身分無關——flow_control / task_survey / flow_engine / notify_config 都在用;mfa→notification 依賴改 INotifier port 由宿主注入,範式照抄 jedi-auth UserChangePasswordService 現有做法);agent 機器身分(mTLS / X-Agent-Uid)明確不併——身分套件管「人」、jedi-remote-agent 管「機器」,兩套認證體系平行。合併範圍除四支套件外,主專案下列身分性質程式一併收進套件common/middleware/jwt_mw.py(170 行,JWT 驗證的唯一 HTTP 入口)、socketio_auth.py 的驗簽/blocklist 段(socket 身分入口)、user_context_builder.py(57 行,allowed_tenant_paths 的唯一產生點——RLS 鑰匙)、安全政策定義(security_policy 約 300 行的政策 schema/DEFAULTS——登入鎖定/密碼週期/JWT 效期/強制 MFA;值的存放留宿主)、tenant_provisioning_service.py(214 行,租戶開通;販售模組清單常數拆出留宿主)、root_admin_reader.pytenant_admin_role_flag.py(合併後改走 domain service,消滅 raw SQL 繞道)、使用者批次匯入編排(寄信 port 化)。UserContextDTO 留 jedi-common(它是 session_scope() 的直接輸入,搬走會讓 jedi-common 反向依賴身分套件)——DTO 當防腐邊界、組裝邏輯進 jedi-iam。X-Tenant-ID 作用租戶覆寫收進套件並補授權檢查(現況只信 header、無任何檢查)。數據支撐:①login→auth 21 處 import 且穿透到 infra 層(password_adapter 直接 import UserRepoImpl)=一個套件被切成兩個目錄;②近三次發版五支全部同批 bump=「獨立演化」從未兌現;③B 類通用膠水 1,300 行(登入編排/MFA 分派/JWT 接線——任何產品都要重抄)+C 類純重複 320 行(LoginConfig 組裝 ×4、OTP 信組裝 ×2 逐字元相同、DI 重複宣告 ×5 container)=第二個產品的重工稅;④死鏈三條(mfa send_otp_mail+11 個測死代碼的測試、圖形驗證碼全鏈 FE 零呼叫、login_logs 五層 8 檔 DB 0 列)。與 D3 的關係:不衝突,是 D3 判準的延伸——D3 排除獨立 jedi-authz 的三理由(新增依賴邊/強迫裝兩包對版/無單獨消費場景)逐字適用於 jedi-login。排序=第 2.5 階段(第二階段表收斂之後、第三階段補殼之前);理由:補殼成本與套件數成正比——先合併再補殼=補 1 次,先補殼再合併=補 5 次然後扔掉 4 次。名稱定案 jedi-iam(2026-08-30 PM 拍板改定,取代開發期暫名 jedi-identity):IAM=Identity and Access Management,業界類別正名(Keycloak/Auth0/Okta 皆屬 IAM 解決方案);identity 一詞僅涵蓋「你是誰」半邊,本套件實質是身分+存取管理(authz 主體域/capability/安全政策/租戶覆寫檢查)全疆界,用 identity 太狹隘。原 2026-08-30 首輪定名 jedi-identity 的推導(「Identity Platform 是業界類別詞」)經 PM 指正不精確——那是廠商行銷用語,類別正名是 IAM。被排除:沿用 jedi-auth(auth 慣例偏認證,承載不了合併後三倍內容物)、jedi-authz(只指授權小角,方向相反)。改名執行=CM-1464(.16 之後、.18 publish 之前一次改;2026-08-30 執行完畢)。jedi_identity 不留轉發殼——它從未推上 Nexus、無任何外部消費者,留殼只會養出第二條 import 路徑;守衛測試已焊死舊名不得復活(test_module_boundaries.py)。被合併的四支舊名(jedi-auth / jedi-login / jedi-mfa / jedi-captcha)維持轉發殼——它們已發版在外,第三階段才下架。前置確認:已確認(2026-08-30)——user 確認 jedi-* 目前僅 Guidant AI 產品線消費,無 breaking change 風險。順手清理四項+依賴大掃除:①jedi-department 下架(與 org_units 同概念兩份實作、無 tenant_id 無 path 不支援多租戶、主專案 pyproject 已註解未安裝——留著日後有人裝回來就是兩張部門表);②「判 root tenant」三份複製收斂為一份(jedi-common _session_paths_have_root() 為 canonical,jedi_auth/authz/platform.pycapability_service.py 兩份改為呼叫——三份漂移=授權事故);③roles.is_admin 殭屍旗標連呼叫端刪除(tenant_admin_role_flag.py 檔頭已自承);④jedi-login infra/test_local/ 手測腳本(265 行)清出正式目錄。加碼:合併時 pyproject 依賴大掃除——4 個虛掛依賴(captcha 的 Flask-JWT-Extended/bcrypt、notification 的 bcrypt、auth 的 babel 疑似)+5 支套件的 testcontainers/pytest 錯放主依賴,一併修正。反悔條件:若未來出現「只要登入不要帳號管理」的真實消費者(如純 SSO gateway 產品、user 存外部 IdP),login 獨立才成立。
D10 問卷疆界合併(2026-08-30) 成立——task_survey(作答層)與 jedi-survey(問卷設計)合併為問卷疆界套件;P11 從「抽新套件」改寫為「合併」。鐵證:資料庫有兩條外鍵直接跨過套件與主專案的邊界——套件邊界不可能靠 DB 外鍵縫合,原「把作答層抽成獨立新套件」技術上不可行;2026-03 schema 搬遷腳本刻意把作答表與問卷表放同一 schema,設計意圖即「問卷=設計+作答」。反悔條件:出現「只要問卷編輯器、不要作答」的真實消費者(如純表單設計器產品)。詳 boundary-map.md。
D11 檢測疆界——device 不併(2026-08-30) device 不屬於檢測疆界;P9 改為「detection_tools+detection_execution+common/ 檢測碼」,不含 device。證據:檢測程式對 jedi-device 引用 0;綁 device 的任務 3,012 筆中檢測型 0 筆;商業模型不同(device 是 25/25 租戶標配、檢測是 6/25 加購模組)。device 真正歸屬=資產盤點語境,形態=獨立插件補殼。反悔條件:未來檢測改為「掃描目標必須來自資產主檔」的產品設計。
D12 OSCAL 疆界改寫(2026-08-30) 方向同意:真三角的第三邊是 flow_control(62 條)而非 module_frame(18 條),且依賴方向與原 §7 P13 所寫相反——oscal 應用層通用件併入 v2、module_frame 另立、依賴方向定為 oscal → flow_control 單向附加開工門檻:P13 開工前先派一棒查證「v2 app service 為何被 77 條 RepoImpl 繞過」——答案決定是「搬應用層進套件」還是「在 v2 內補編排層」,查證通過才改寫。查證已完成(2026-08-30,CM-1462):77 條中 97% 為服務層缺能力(讀取面未開放 41+寫入面缺 21)、僅 2 條便宜行事——原設兩選項皆不成立(編排層已存在且在用;應用層含 GRC 產品知識不宜進套件),查證棒建議中間路線「套件補讀取面+缺口寫入、應用層留主專案」,改寫方向待決策者拍板;報告見 docs/analysis/2026-08-30-oscal-v2-repoimpl-bypass-attribution.md。
D13 三支退役(2026-08-30) jedi-oscal v1(可退役,七項證據齊備,順帶消 AGPL 依賴)、jedi-resource-store(殭屍——程式碼零引用、資料表四環境從未建立、路由 2026-02 已刪,併入既有 CM-1143 追蹤)、jedi_system_log(一載入即炸——與 jedi-common 宣告同一張表,import 即錯)三支退役。執行方式:先標 deprecated 觀察一版再刪(防 Nexus 上有未查證的四 repo 以外下載者);jedi_system_log 屬「會炸的碼」優先處理。jedi-log 不整支退役——拆兩半:API 存取紀錄活著(DB 10 萬筆)留、炸的那半(jedi_system_log)刪。2026-08-30 user 拍板追加:jedi-department/jedi-resource-store 即刻退役執行(首腦四面查證零使用——department 主專案零引用/venv 未裝/DB 表不存在/其他套件零依賴;resource-store 程式與 e2e 零引用/表從未建立,惟主專案仍 pin 0.0.11)。已落地:主專案拔 resource-store pin+清 department 註解殘行;monorepo 兩包 README 頂部退役標記+pyproject description 前綴 [DEPRECATED](不動版號不 publish,目錄保留觀察期)。
D14 jedi-bulletin 去留(2026-08-30) 維持獨立套件(user 定案:公告是可拔去其他產品使用的插件,有複用前景);被排除方案=下架收回主專案(boundary-map 原建議,基於「套件 408 行 vs 主專案重寫 406 行」的形態稅論——user 以複用前景否決)。其對身分名冊/通知的依賴照 D16 基礎依賴 port 化通則處理,第三階段照補插件殼。
D15 ext 盤點裁決三件(2026-08-30) CM-1449 首批對象改為 compliance.project_extensions——盤點證實 auth/user 域無可收斂延伸表(totp_secrets 是刻意安全邊界、user_tenants/user_org_units 根本是關聯表非延伸表),project_extensions 是全庫 190 張表中唯一明確收斂對象(4 欄全帶業務邏輯、與主表 1:1 零缺列),也是「跨套件邊界長出側掛」的典型示範;主要風險=14 處手寫 SQL JOIN 散在 9 檔、主表屬 jedi-project 套件(加欄位走套件異動規範)。②**assessment_plan_extensions 孤兒問題(193 列全對不上主表)另開獨立 case 查證**——刪表 vs 修斷鏈是相反動作,查清前 CM-1449 跳過此表。③JSONB 容器定位調整:由「消化存量的手段」改為「預防性建設——今後新客製一律走容器、不再開側表」;理由=盤點證實本系統的側掛表不是客製欄位長出來的、是跨套件邊界長出來的,9 張中純展示型 0 張。
D16 基礎依賴 port 化通則(2026-08-30,入插件契約) 套件對「基礎能力」的依賴,一律判「疆界內知識 vs 疆界外服務」:疆界外服務(誰是使用者/怎麼發通知/檔案存哪/設定值放哪)→ 一律 port 化,套件只宣告需要的服務形狀、宿主接線時注入;疆界內知識留套件。標準 port 四張:身分脈絡包三名冊(IUserNameResolver/ITenantResolver/IOrgUnitResolver,已落 jedi-common)、INotifier(通知)、檔案存取介面(file-upload)、設定讀取。唯一例外=jedi-common——允許直接依賴的地基(session/查詢基底/例外類),不 port 化。第三階段每支補殼必辦:把該套件直接 import 其他套件之處換成標準 port。終局圖景:一層地基(jedi-common)+一排彼此不直接相依的疆界插件,插件間協作全經宿主接線盤——拔走任一支時把接線盤上的線重接到新產品實作即完成移植。
D17 資料關聯三律(2026-08-31,入插件契約) 表與表的關聯不靠外鍵縫合疆界,改用三條判斷律——外鍵是資料庫自己執行的規則,塞不進 port(程式碼可以「不直接認識」,外鍵不行),因此疆界切分必須在資料層另有一套判準。① 想建外鍵=兩張表該住一起:天天連表查、要同生共死的資料,代表同一個能力被切錯了,正解是合併疆界而非硬拆——D10 問卷疆界合併(設計表與作答表跨界外鍵)即此律的鐵證案例,本條把該個案通則化。② 真跨疆界=軟參照:A 表只存 B 的識別碼(id / uid / 帳號),不建外鍵約束;要顯示名稱走名冊 port(D16 三名冊)批次問,查不到必降級顯示識別碼、絕不炸——jedi-log-forwarding 已是實作樣板,「禁止套件 JOIN 宿主 user / tenant / org 表」(D8 身分脈絡標準件既有禁令)是本律的既有特例。③ 流程耦合=事件/port,連識別碼都不存:「B 發生事、A 要知道」是流程通知不是資料關聯,走 port 呼叫或事件,事過境遷不留關聯——INotifier 即此類。業界對應:律①=DDD「兩個領域老要互摸對方的表=邊界劃錯」;律②=GitLab loose foreign keys、微服務 database-per-service、DDD reference-by-ID、Shopify 禁跨模組 JOIN(CI 強制掃);律③=事件驅動架構。已知代價與收拾方式:軟參照後資料庫不再擋「指到已刪除的資料」,由兩件事收拾——「查不到必降級」(律②內建)+定期清理孤兒資料(背景作業,比照 GitLab loose FK+清理器;本案尚未建置,隨第四階段各疆界落地時補)。適用範圍:第四階段每支候選(P12 participant hub/問卷合併/flow_control 拆出/P13 OSCAL)判斷疆界切分時一律依此三律;既有跨界外鍵不回頭全面拆除,隨各疆界抽取時逐案處理(拆到誰才判誰)。與 D10/D11 的關係:D10(問卷合併)是律①的先例、D11(device 不併檢測)是「無外鍵亦無共生關係→本就不同疆界」的反面印證,兩者皆不因本條改判。view 條款(2026-08-31 補):DB view=存在資料庫裡的跨疆界查詢,同受本三律管轄;但守衛測試掃 Python 掃不到 view(CM-1474 實證——.12 雙寫守衛漏掉 vw_user_job_queue),故 view 歸屬必須人工列冊(現存 4 張的歸屬表見 CM-1478 卡)。 反悔條件:若未來出現「跨疆界一致性必須由 DB 保證」的硬需求(如金額結算類),該處回到單一疆界內處理,而非把外鍵加回跨界。
D18 設定 schema 申報制(2026-08-31,D6 config 插槽升格正式規格) 設定的 schema 進套件、值與存放留宿主、模組開關表永遠留宿主——套件管規格書、主產品管實際的值。① schema 進套件:套件於 register() 時申報自己的設定 schema(鍵名/型別/預設值/驗證規則/作用域),隨包出貨;② 值與存放留宿主:宿主照舊集中存 system_configs,並拿套件申報的 schema 驗證寫入——套件不自建設定表、不決定值存哪;③ 模組開關表永遠留宿主:「哪些模組對這個租戶開啟」是宿主的組裝決策,不隨任何套件走(套件不該知道自己有沒有被啟用)。三項補充(2026-08-31 討論定案)(a) 作用域為 schema 的必填欄位——分系統級(這個部署:LDAP 連線、儲存後端,平台管理員改)/租戶級(這個客戶:通知偏好,租戶管理員改)/租戶可覆寫系統級(平台給預設、客戶可換自己的:SMTP 信箱伺服器)三種;儲存機制現成(system_configs 已有 tenant_id(tenant_id, group, key) 唯一鍵),不需新表(b) 預設活在 code、DB 只存差異——讀取時查無列即回 schema 內建預設,免除 seed 時序問題(套件裝上就有預設值可用,不必等 migration 跑完);若確實需要 seed,只補缺鍵、絕不覆蓋既有值(冪等鐵則——覆蓋會把客戶調過的設定打回原廠)。(c) 讀取 fallback 鏈由套件申報、宿主執行:租戶值→系統值→schema 預設,全鏈皆無則 fail loudly(不可靜默回 None 讓呼叫端當沒設定);客戶只能改自己作用域內的值、寫入須過 schema 驗證、跨作用域寫入須有授權守門。業界同構:GitLab/Odoo/WordPress register_setting()/K8s CRD——皆為「插件宣告形狀、平台管存放」。first case:2.5 階段 security_policy.py(七個設定鍵 schema 進套件、值留 system_configs)已是本制的實例,本條把它升格為正式規格。加分項(非必辦):設定頁由申報 schema 自動生成表單——不必每加一個設定就手刻一次畫面。適用範圍:第四階段新抽套件一律照辦;既有 20 支套件於第三階段補殼時回頭套用(有設定者才做,無設定者免)。

插件契約補充:身分脈絡標準件(D8 併入 D6 契約)

  • 規則:凡套件 API 會吐 created_user / updated_user / tenant_id / org_unit_id 或業務性 user 參照(如 matched_user_id)者,套件必須內建對應名冊 port 並在 app 層批次 enrich*_user_name、租戶名、單位名);純引擎型無此輸出者免做——標準是「有吐才要補」,不是每支硬裝。
  • 名冊 port 一族(皆同構:批次 id→名稱、選填、不注入優雅降級不炸):
    • IUserNameResolver——帳號批→顯示名稱。P3 jedi-log-forwarding 已有樣板(批次防 N+1、選填、降級顯示帳號),為本標準件的參考實作。
    • ITenantResolver——tenant_id 批→租戶名稱。
    • IOrgUnitResolver——org_unit_id 批→單位名稱。
  • 收斂設計:第二階段在 jedi-common 定義共通「身分脈絡包」(identity context)——套件宣告需要哪幾張名冊、宿主接線時一次注入一組,避免 20 支套件各自定義微妙不同的簽名再度發散。
  • 多租戶欄位規則(引用 P4 先例):tenant / org_unit 欄位在 001 腳本建 nullable、002(需宿主 RLS 生態)才收緊 NOT NULL——套件必須在多租戶與單租戶宿主都能活
  • 禁止:套件 JOIN 宿主 user / tenant / org 表、認得宿主身分模型——一律透過名冊 port 問。
  • 現況註記:P1 / P2 / P4 / P5 未內建名冊(其管理面不吐稽核欄位,當時無需求)——不回補,第三階段統一過一輪時順手做;主專案現有 28 處 app 層自行補名屬歷史重工,隨第三階段各套件升級逐步刪除。

4. 現況盤點

4.1 全模組四分類

分類 模組 處置
① 產品核心(不抽) grc(236檔)、oscal(193)、module_frame(79)、associations(67)、participant(90)、project(25)、project_summary_report(36)、task_survey(65)、detection_tools(99)、detection_execution(28)、evidence_classification(42)、device、subtask_status_history、information_system 殼、flow_engine 殼 第一階段不動;抽取路徑見 §7 凍結路線圖
② 既有 jedi 套件的殼(免抽) auth、survey、bulletin、notify_config、system_config、system_menu、captcha、log、issue/feedback、upload_file 主專案剩 route + DI wiring + 專案特有 enrich,正是設計上「該留主專案」的部分
③ 抽取候選(本案主體) ai(6檔)、integrity(+common/integrity ≈23)、log_forwarding(+common/log_forwarding ≈32)、remote_agent+agent_task(+agent_auth ≈87)、license(+common/license ≈44) P1–P5 逐支抽出
④ common/ 分類搬遷 通用 util → jedi-common;authz 主體域 → jedi-auth;業務 error code/enum → 歸位回各模組 P0 歸位、P7/P8 上移

4.2 耦合分析重點

  • P1–P5 候選全部是葉節點:零跨模組 outgoing(license 僅 1 條對 notification 的細線),且除 DI 註冊行外無任何模組 import 它們。
  • hub 排行:participant(in-degree 10、被 import 60+ 次,但 out-degree 僅 8——凍結路線圖的鑰匙)、flow_engine(in 9)、notification(in 8 但廣而淺)、system_config(in 7)、grc(in 7 + out 11,雙向樞紐)。
  • di_containers/containers.py 是隱形 hub(401 行、43 個 import):每次抽取都要同步改註冊,是每支套件的固定成本,各 arc 驗收條件都含這一項。

4.3 必須先修的架構債

內容 影響
uploadfile / upload_file 雙模組 api 層用 uploadfile(舊 route)、app/infra/di 用 upload_file(managed file upload),同功能兩套命名並存 抽取地雷;P0-① 合併
common/ 的 9 條反向 import common/authzdomain.oscal(3)、domain.participant(2);1 條 → infra.integrity;3 條 → di_containers.containers 違反分層方向;不斷掉則 P7/P8 上移後套件對主專案循環依賴。其中 5 條在 authz 資源域(D3 拆半後不隨包搬,但仍該斷);P0-② 處理
模組專屬 error code / enum 錯放 common/ grc_error_code(94 處)、module_frame_error_code 等 8 支 + participant_enum(16) 等業務 enum 放在 common/codecommon/enum 讓 common/ 看起來比實際「通用」,混淆 P7 搬遷面;P0-③ 歸位

4.4 common/ 三分法(P7/P8 的搬遷清單基礎)

去向 內容 熱度
jedi-common(P7) util/response_util.py124 處 import、123 處來自 api 層,全 repo 最熱單檔)、common_utilaudit_logaudit_nicknameserialization_utilredis_client_utilexcel_utilfile_utilpdf_utilsavepointscheduled_timecode/error_code.py(45)、enum/schema_code.py(60)、http_code_enumdao_error_enum util 267 處 / 43 模組
jedi-auth(P8) authz/ 主體域半包:platform.py(9)、admin.py(3)、capability.py(2)、decorators.pysigned_token.py authz 全包 140 處 / 32 模組
留主專案 authz 資源域(project/ssp/workflow/menu_license_filter)、各模組 error code/enum(P0 歸位)、OSCAL/CMMC 業務工具(control_id_matcher、profile_extractor、cmmc yaml…)、guard 群(participant/round/workflow_project)
隨模組帶走 common/integrity/(→P2)、common/log_forwarding/(→P3)、common/util/agent_auth/(→P4)、common/license/(→P5) 各自僅該模組使用

5. 詳細設計(P0–P8 各 arc)

P0 前置清理(不抽東西,先還債)

子項 內容 要點
P0-① 合併 uploadfile / upload_file 收斂為 upload_file 單一命名;api route 檔搬併、config/app_modules.py 與 containers.py 註冊同步;歷史 URL 路徑不變(只動 python 模組名不動 endpoint path)
P0-② 斷 common/ 9 條反向 import authz→domain 的 5 條:resolve 邏輯改由呼叫端傳入 entity 或改 port 注入;→infra.integrity 1 條:改 DI 注入;→di_containers 3 條:改 lazy import 或注入。完成判準:`grep -rE "^from (domain
P0-③ error code / enum 歸位 8 支模組專屬 error code + 業務 enum 從 common/codecommon/enum 搬回各模組目錄(如 app/grc/code/);im­port 路徑變動用 IDE 級全域替換 + 全量 import 檢查
P0-④ 守衛測試基礎 test/test_module_boundaries.py 骨架:斷言 common/ 無反向 import、後續各套件抽出後逐支加「不得 import 主專案」斷言
P0-⑤ grc → flow_control 改名(D5) 與 P0-③ error code 歸位同批 import 替換執行(省一輪全域替換與全量驗證)。目錄/類名/DI 註冊改,error code 字串值、API URL path、DB 內容不動。完成判準:grep 全 codebase 無 app.grc / domain.grc / infra.grc import 殘留;grep -rn "GRC_" (error code 字串值)確認未被改動;BE 重啟 + 稽核主流程手測正常

驗收:上述 grep 為 0;BE 啟動正常;檔案上傳、任一稽核頁面手測正常;flow_control 改名三判準(import 殘留 0 / 字串值未動 / 主流程手測)全過。

P1 jedi-ai-bot(SOP 練手+插件契約首例)

  • 內容物(D6 升級後):api/ai/(blueprint / route)與 app/ai/(AiBotService,Anthropic Claude + Redis 對話)一併進套件——套件自帶 api 層 + 預設 DI container + register(app, adapters) 註冊入口(本模組無 migration,migration 隨包機制的首例落在 P2–P5 中第一支有表的套件)。6 檔,最小案例。
  • 契約定義責任:P1 是 D6 插件契約的第一個實作——register() 簽名、blueprint 掛載方式、container wiring 慣例、拔掉測試步驟,全部在本 arc 定案並寫進 SOP checklist,P2–P5 照抄。
  • port:無——只依賴 jedi_common 與 Redis client(隨包或注入均可,傾向注入 redis client)。
  • D7 責任:harness +接入 README 由 P1 首做並寫進 SOP checklist——dev_app.py + compose(本模組吃 Redis,compose 起獨立 Redis)+套件測試獨立跑;接入 README 含 port 清單 / 註冊行 / quickstart。
  • 驗收:套件上 Nexus、主專案 pin、AI 聊天手測正常、守衛測試綠、拔掉測試通過(註解 app_modules.py 註冊行 → BE 正常啟動、AI 聊天路由消失、其餘功能不受影響)、harness 起得來且套件測試在 harness 內全綠(D7)接入 README 完成且照它 10 分鐘能在 harness 重現 quickstart(D7)本 arc 同時產出「抽取 SOP checklist」文件(供 P2–P5 復用,必含拔插驗證與 harness/README 步驟)。

P2 jedi-integrity

  • 內容物app/infra/di 的 integrity 模組 + common/integrity/ 全包(lockdown / startup_gate / runtime_check / tamper_marker / forensic / lc_report / unlock)。
  • 注意:startup gate 在 main.py 啟動鏈上被呼叫——套件需提供清楚的公開入口函式;與 FR-064 的 manifest/簽章產線(scripts/build/)的檔案座標約定要在套件 README 寫明。
  • port:無跨模組線。config.config 的讀取改為初始化參數傳入。
  • 驗收追加(D6):拔掉測試通過;插件契約形式照 P1 定案的 SOP(自帶 api 層如適用 / container / register 入口 / migration 隨包)。
  • 驗收追加(D7):standalone harness +接入 README 齊備,形式照 P1 SOP。

P3 jedi-log-forwarding

  • 內容物:log_forwarding 模組全層 + common/log_forwarding/(forwarder / gelf_handler / settings_reader)。
  • 要斷的線:1 條 jedi_auth 細線(設定 CRUD 的權限判斷)——本來就該走主專案 route 層守門,套件內移除。
  • 注意:QueueHandler 掛載點在 logger 初始化鏈,同 P2 提供公開入口函式;「轉發失敗不拖垮主服務」的靜默降級行為要有套件內測試。
  • 驗收追加(D6):拔掉測試通過;插件契約形式照 P1 定案的 SOP。
  • 驗收追加(D7):standalone harness +接入 README 齊備,形式照 P1 SOP。

P4 jedi-remote-agent

  • 內容物remote_agent(註冊/enroll token/心跳)+ agent_task(派工/查詢)+ common/util/agent_auth/(ca/tls/jwt/heartbeat mTLS)。約 87 檔,第一階段最大宗。
  • 要斷的線:remote_agent → jedi_file_upload(agent 上傳結果檔)保留——jedi 套件依賴 jedi 套件是合法邊(比照 jedi-issue → jedi-file-upload 先例)。
  • portIAgentTaskPayloadProvider 之類的派工內容組裝介面——檢測派工的 params 組裝屬產品知識,留主專案實作注入;套件只管「派工信封」的生命週期(pending/領取/回報/逾時)。
  • 注意:憑證與 CA 檔案路徑全部參數化;detection_tools 對 agent_task 的消費照舊(import 套件)。
  • 驗收追加(D6):拔掉測試通過;插件契約形式照 P1 定案的 SOP。
  • 驗收追加(D7):standalone harness +接入 README 齊備,形式照 P1 SOP。

P5 jedi-license-runtime

  • 內容物:license 模組全層 + common/license/(engine / machine_fingerprint / public_keys / schema)。
  • 要斷的線:1 條 → notification(到期通知)。套件內定義 INotifiernotify(recipients, subject, body) 級別的窄介面),主專案 adapter 包 jedi_notification。
  • 注意:PUBLIC_KEYS 常數的更新流程(多環境簽發鑰四步一組)要寫進套件 README;common/integrity 若有交叉引用,依 P2 先行的套件邊界處理(license-runtime 依賴 jedi-integrity 是合法 jedi 間邊)。
  • 驗收追加(D6):拔掉測試通過;插件契約形式照 P1 定案的 SOP。
  • 驗收追加(D7):standalone harness +接入 README 齊備,形式照 P1 SOP。

P7 jedi-common 擴充

  • 內容物:§4.4 第一列清單上移。分兩批 commit:①response_util(影響 124 檔的解析位置,單獨一批全量回歸)②其餘 util + error code 基底 + 通用 enum。
  • 硬要求全量回歸——既有 pytest 全跑 + 主要頁面手測清單(因 jedi-common 被 42 個模組、20 個套件依賴,此 arc 是全案風險最高點之一)。
  • 注意:jedi-common 版本 bump 後,monorepo 其他套件的 >= 約束不需動;主專案 poetry update jedi-common 一次收攏。

P8 authz 主體域併 jedi-auth

  • 前置:P0-② 完成(反向邊已斷)、P7 完成(decorators 若引用通用 util,先等它們就位)。
  • 內容物common/authz/ 的 platform / admin / capability / decorators / signed_token 進 jedi-auth 新子包 jedi_auth/authz/;資源域四支留原地。
  • 相容策略common/authz/__init__.py 保留 re-export shim(主體域符號轉 import jedi_auth.authz),消費端 32 個模組零改動;shim 標 deprecated,後續新 code 直接 import jedi_auth。
  • 驗收:admin / manager / auditor / 一般使用者四種角色的權限行為全數與改前一致(比對主要守門點清單逐項手測)。

6. 拆分表(8 arc × 依賴 × 驗收)

Arc 依賴 可平行 驗收條件
P0 前置清理(含 grc→flow_control 改名)|進行中(平行 session) 起點 反向 import grep=0;上傳功能手測正常;守衛測試骨架進 test/;grc 舊 import 路徑殘留 0、error code 字串值未動、稽核主流程手測正常
P1 jedi-ai-bot|與 P0 檔案零重疊,可平行派工 無(P0 非硬前置) 與 P2–P5 平行 套件上 Nexus + pin;AI 聊天手測;插件契約定案(register 簽名等)+拔掉測試通過harness+接入 README 首例(D7);SOP checklist 產出
P2 jedi-integrity 建議在 P1 SOP 之後 套件 + pin;落地版 startup gate 手測;守衛測試;拔掉測試;harness+接入 README
P3 jedi-log-forwarding 同上 套件 + pin;轉發到測試 syslog 收到 log;守衛測試;拔掉測試;harness+接入 README
P4 jedi-remote-agent 同上 套件 + pin;agent 心跳 + 檢測派工端到端手測;守衛測試;拔掉測試;harness+接入 README
P5 jedi-license-runtime 同上 套件 + pin;license 啟用/到期流程手測;INotifier adapter 生效;守衛測試;拔掉測試;harness+接入 README
P7 jedi-common 擴充 P1–P4 完成後(讓新套件先穩定) jedi-common 新版;pytest 全綠 + 頁面手測清單;response_util 批單獨回歸
P8 authz 併 jedi-auth P0-② + P7 jedi-auth 新版;四角色權限行為一致;shim 生效、消費端零改動

每個 arc 共同的固定項目:di_containers/containers.py 註冊同步、config/app_modules.py 同步(如適用)、jedi-packages.md 補該套件一段、Notion 子卡回寫、extract→publish→pin 順序紀律。


7. 第二~四階段與終局選項(D8 全解凍後的全案路線)

2026-08-30 D8 拍板:原「凍結路線圖」全解凍,「等第二消費者」原則廢除——整併本身即目標。各階段先後與交錯於第一階段(P0–P8)總結時排定;下表順序為建議序。

第二階段:ext 表收斂+JSONB 擴充容器

2026-08-30 盤點定案(D15,phase2-ext-table-inventory.md):掃 190 張實體表,真正的延伸表 9 張、純展示型 0 張——本系統的側掛表不是「客製欄位」長出來的,是「跨套件邊界」長出來的(主表在套件、產品欄位沒地方放才側掛)。故本階段實作重點由「JSONB 容器消化存量」調整為「跨套件側掛欄位收回主表正式欄位」;JSONB 容器定位改為預防性建設——今後新客製一律走容器、不再開側表(查詢能力已由 CM-1448 落地 jedi-common)。

  • 盤點:✅ 已完成(CM-1447,2026-08-30)——9 張延伸表去向:收回主表 1(project_extensions)、留置 6、待查證 1(assessment_plan_extensions 孤兒表,另開 case)、結構異常另記 1(ssp_system_characteristics 缺唯一性約束)。
  • 收斂實作(CM-1449)首批對象=compliance.project_extensions(D15;原「auth/user 優先」經盤點證實無收斂對象,已改)。「只加不破」五步搬遷(加欄位→回填→雙寫期→逐處切讀取→觀察後 drop)+帶舊資料升級驗證;主要風險=14 處手寫 SQL JOIN(散 9 檔,改漏不報錯只靜默少過濾軟刪除)+主表屬 jedi-project 套件(加欄位走套件異動規範)。
  • jedi-common 查詢層補能力:✅ 已完成(CM-1448,2026-08-30)——JSONB 擴充欄位查詢/排序(_ext_* 前綴族)、身分脈絡包三名冊、SessionMixin 正名皆落地,未發版。
  • 判斷口訣:只是「多記幾個值」→ JSONB 容器;要「拿來運算/關聯/約束」→ 正式欄位(或客戶側開表)。

jedi-common 基底類正名案(2026-08-30 調查定案)

  • 調查結論session/database/ 頂層 base_repository.py(7 行 session property)不是舊代殘留——它是 lazy session 提供者(mixin),repository/base_repository_impl.py 的完整查詢基底自己就繼承它(class BaseRepositoryImpl(IBaseRepo[T, Q], BaseRepository, ...))。兩者是「連線底座 vs 完整基底」的零件關係,不是新舊兩代。
  • 合法用法認定:主專案 5 檔(cloud_integration 3 支 raw-SQL repo/bulletin link 表/upload_file HTTP adapter)與老套件 27 處直接繼承底座,多屬「特殊 repo 不適用完整基底、只需 session」的合法情境(同 CLAUDE.md「不能繼承 BaseRepositoryImpl 時自己寫 @property session」條)——不做汰換
  • 真問題=命名混淆:底座與 repository/base_repository.py(查詢介面)同名不同角色,會誤導讀者當成待淘汰舊版——本案調查即因此差點誤發一輪假清理。
  • 第二階段動作三條
    1. 底座正名(如 SessionMixin;挪位與否屆時定),舊名留轉發(32+ 處引用零即刻改動)。
    2. 頂層 base_model.py真重複(與 model/base_model.py 內容漂移)且全生態 0 引用——直接刪。
    3. 第三階段各套件升級棒「順手看一眼」該套件對底座的繼承是否真屬特殊 repo(預期多數合法),不再列為汰換欠帳
  • 教訓註記:同名不同角色的基底類是「假清理」誘因——收斂靠正名,不靠強制遷移。

第 2.5 階段:jedi-iam 身分套件合併(D9)

插在第二階段(表收斂)之後、第三階段(補殼)之前——先合併再補殼=補 1 次;先補殼再合併=補 5 次扔 4 次。完整決策內容與數據支撐見 §3 D9。

動作 內容
四支合一 jedi-auth+jedi-login+jedi-mfa+jedi-captcha(降級為 turnstile 小模組)→ jedi-iam(暫名 jedi-identity,PM 2026-08-30 定調改名);舊套件名留轉發過渡
主專案身分程式收進套件 jwt_mw(JWT 入口)、socketio_auth 驗簽段(socket 入口)、user_context_builder(RLS 鑰匙產生點)、安全政策定義(值存放留宿主)、tenant_provisioning(販售模組常數留宿主)、root_admin_reader/tenant_admin_role_flag(改走 domain service)、使用者批次匯入編排(寄信 port 化)、X-Tenant-ID 覆寫(並補授權檢查
明確不併 jedi-notification(基礎設施,12 消費點多與身分無關;mfa 發信改 INotifier port);agent 機器身分(mTLS/X-Agent-Uid,歸 jedi-remote-agent);UserContextDTO 留 jedi-common 當防腐邊界(組裝進套件)
順手清理 ①jedi-department 下架(與 org_units 重複且無多租戶)②「判 root tenant」三份複製收斂為一份(jedi-common canonical)③roles.is_admin 殭屍旗標連呼叫端刪④jedi-login infra/test_local 手測腳本清出;加碼 pyproject 依賴大掃除(4 虛掛+5 支測試依賴錯放)
前置確認 ✅ 已確認(2026-08-30):jedi-* 僅 Guidant AI 產品線消費

疆界盤點案(FR-069.9,第四階段前置,與第二階段平行)

純分析案不動碼。第四階段的開工門檻——P6/P9–P13 各棒開工前必須先有疆界地圖定案。動機:以前按技術功能切太碎,26 支裡不少是「同一個能力被切成幾半」(jedi-iam 案已證實一組);先畫清疆界再動工,避免抽完又要合。

方法(照 jedi-iam 案的同一套判準與分析深度):①實際耦合數據(跨套件 import 具體到符號、穿透層級)②發版歷史(獨立生命有無兌現)③主專案膠水量化(A 產品特定/B 通用重寫/C 純重複三分類)④死碼盤點⑤pyproject 依賴健檢。

待驗證的疆界候選五組(初步假設,以數據為準):

# 候選疆界 內容物 對既有計畫的影響
1 檔案疆界 jedi-file-upload+jedi-resource-store
2 問卷疆界 jedi-survey+主專案 task_survey 改寫 P11——從「抽新套件」變「合併成疆界套件」
3 檢測疆界 jedi-device+主專案 detection_tools/detection_execution 改寫 P9
4 OSCAL 疆界 jedi-oscal(退役查證)+jedi-oscal-v2+module_frame+oscal 應用層 改寫 P13
5 追蹤疆界(弱候選) jedi-issue+jedi-bulletin+主專案 feedback 可能只是「都很小」而非同疆界,待數據

另兩項退役查證:jedi-log(vs 新日誌體系的重疊度)、jedi-oscal v1(vs v2 的取代狀態)。

產出物:「最終疆界地圖」——26 支現有套件+主專案候選模組的完整去向表(合併/獨立補殼/退役/下架),供 user 拍板後改寫第三、四階段的棒次表

願景:套件庫從 26 支細粒度零件收斂為約 12–15 支輪廓清楚的疆界套件。

第三階段:既有老套件升級插件模式

身分族已於第 2.5 階段合併為 jedi-iam——本階段補殼時身分族僅 1 支。補殼對象清單已按疆界盤點結果(2026-08-30 拍板 D10–D14)更新如下——同疆界者先合併再補殼,避免補完又扔。

每支補齊 D6/D7/身分脈絡標準件(老套件缺的是「插件的殼」,最難的解耦已完成,工程量比新抽輕),並執行 D16 基礎依賴 port 化(把直接 import 其他套件之處換成標準 port 四張——這是每支補殼的必辦項)。主專案側同步把每支的接線收斂成「一個接線檔」,並隨升級逐步刪除 28 處 app 層自行補名的歷史重工。

隨棒必做(追蹤卡 CM-1461):2.5 階段與本階段各棒動到某模組的 route 註冊時,順手拔除該模組的裸路徑死端點(62 支總帳見卡——同 Resource 雙路徑註冊缺 handler、打了必 500 但 FE 零裸打;CM-1454 Postman 掃描發現),拔前確認 e2e/agent 無呼叫,拔後回卡勾銷。

分級 套件 處理
完整升級 jedi-iam(2.5 階段產物,首棒示範)、jedi-file-upload(唯一有第二使用者的套件——jedi-issue 在用)、jedi-notification、jedi-flow-engine、問卷疆界套件(D10 合併產物) 完整五件套(api 層/register/harness/README/拔掉測試+適用者補 migration 隨包與名冊)+D16 port 化
輕量升級 jedi-bulletin(D14 定案維持獨立,名冊/通知依賴 port 化)、jedi-system-menu、jedi-system-config、jedi-device(D11 定案不併檢測、歸資產盤點語境)、jedi-information-system、jedi-issue、jedi-log(拆兩半後留下的 API 存取紀錄半) 補 register 入口+README,harness 從簡+D16 port 化
退役/下架(D13,先標 deprecated 觀察一版) jedi-oscal v1(七項證據、消 AGPL)、jedi-resource-store(併 CM-1143)、jedi_system_log(會炸的碼,優先);另 jedi-department(D9 已定下架) 不補殼,不花力氣升級殭屍套件
待另議 jedi-project(boundary-map 建議短期凍結不補殼、長期併「專案疆界」——涉終局選項,未拍板)、jedi-issue 內 58% 死碼去留(gitlab/github 整合 1,191 行——「已廢棄 vs 留給未來客戶」屬產品決策,未拍板) 決策前不動

第四階段:核心抽取(原 P9–P13+P6,全解凍)

形態分流準則(D7-③,每支候選啟動前先過這關)

每支候選開工前,先判「插件 vs 服務化」:

  • 服務化(License Center 模式:獨立部署、網路 API、自有 DB)——適用於有獨立生命週期的能力:自己的發版節奏、自己的擴縮容需求、可能服務多個產品實例(如檢測平台)。邊界是網路協定,想耦合都耦合不了,是最強的解耦形態。
  • 插件(D6 契約:隨包安裝、進程內掛載)——適用於與宿主同進退的能力:跟宿主同版本演進、共享宿主的 DB/auth/tenancy(如 authz、integrity、log-forwarding 這類)。
  • 判準問句:「這個能力壞了,是宿主整個停,還是可以降級繼續跑?」「它需要自己的資料主權嗎?」「同一套實例會服務多個產品嗎?」——三題任一為是,傾向服務化。

棒次順序(2026-08-31 user 拍板定序,卡號 CM-1475–1483 九張連號)——每棒一句排序理由:

棒次 項目 內容 為什麼排這個位置 關鍵事實
4.A CM-1475 地基棒 D17/D18 通則入 §3 決策表+套件分類地圖(架構手冊 package-taxonomy.md)+跨疆界聚合查詢正名搬 infra/readmodel/ 排第一因為後面每棒都讀它——runner 讀不到對話只讀得到文件,通則不落地就每棒重新發明判準;聚合查詢正名是 P12 的硬前置(「我的任務」聚合正躺在即將抽出的人員指派模組裡,SQL 字串裡的跨表依賴 grep 守衛與 harness 都抓不到,誤搬進套件=靜默炸) 8 支聚合 query 約 1,500–2,000 行、每支跨 3–4 schema(盤點見 docs/analysis/2026-08-31-cross-boundary-aggregation-api-inventory.md
4.B CM-1476 AI registry 自註冊 api_registry.py 由硬編碼表改為各套件自註冊,宿主只組裝目錄;順修 2 個指向不存在 provider 的壞條目 排在核心抽取之前、但可與 P12 平行——不改的話每抽一支套件就要回頭改 525 行硬編碼表+14 個 container resolver,抽越多改越多次;與 P12 無共用檔案故可平行 api_registry.py 28 條 API 覆蓋 14 模組;:244:254 兩條 provider 不存在(lambda 延遲求值故起服務不炸,AI 選到才 500)
4.1 CM-1477 jedi-participant(P12) 多層級任務指派(~90 檔) 核心抽取首棒——解核心環的鑰匙:抽完最粗兩條邊自動消失,後續各支才好動;且 out-degree 僅 8,是全部候選裡改動面最小的 解核心環的鑰匙:全專案最大 hub(被 60+ 處依賴)但 out-degree 僅 8——import 名不變原則下,消費端(flow_engine 52 條、grc 43 條)零改動,只需斷自己的 8 條線。抽完核心環最粗兩條邊自動消失,後續各支才好動。TaskAssigneeService 切法已裁(2026-08-31):純 CRUD 隨套件走、跨疆界聚合讀取留主專案
4.2 CM-1478 flow_control 拆出+流程疆界三方設計 稽核執行業務層拆出(拆法「先單純拆出、切分後議」,見下方終局選項段);flow-engine/flow_control/project 三方同席定 route 與 app 層歸屬 排 P12 之後、P13 之前——P12 先解掉最粗的 participant 邊,搬家包袱最小;又必須在 P13 之前,因 D12 已定 oscal → flow_control 單向依賴,OSCAL 疆界設計必須知道 flow_control 自己也會成為套件,否則拆完返工 稽核執行業務層 37 支 service/236 檔;3.4 實查證實 flow-engine 19 條 route 有 17 條吃稽核業務、6,375 行 app/flow_engine 疆界未定(CM-1470 裁併入本案)
4.3 CM-1479 OSCAL 疆界(D12 改寫 oscal 應用層通用件併入 jedi-oscal-v2;module_frame 另立;三角第三邊=flow_control(62 條,非原寫的 module_frame 18 條);依賴方向定為 oscal → flow_control 單向(與原文件所寫相反) 緊接 flow_control 之後——三角第三邊是 flow_control,它定形了 OSCAL 才有邊界可劃 開工門檻(D12):先派一棒查證「v2 app service 為何被 77 條 RepoImpl 繞過」——答案決定「搬應用層進套件」還是「在 v2 內補編排層」。P12 之後做。中間路線已裁採納(2026-08-31):套件補讀取面+缺口寫入、應用層留主專案(CM-1462 查證結論,推翻原兩選項)
4.4 CM-1480 jedi-detection detection_tools + detection_execution + common/ 檢測碼(不含 device——D11 定案,device 歸資產盤點、獨立補殼) 核心環解完才動邊緣——它往外只有 participant/flow_engine/notification 各 1–2 條,那些線在 4.1/4.2 已先斷乾淨 核心邊緣:往外僅 participant/flow_engine/notification 各 1–2 條,全 port 化即可;grc 對它的 7 條反向依賴不需處理(届時 import 套件)。形態分流:檢測平台有獨立生命週期特徵,開工前先過服務化評估
4.5 CM-1481 jedi-evidence-classification AI 佐證分類引擎(~42 檔) 可與 4.4 平行——零 incoming、與檢測無共用檔案 零 incoming;6 條 outgoing 用 IEvidenceSource / IControlCatalog 兩 port 斷
4.6 CM-1482 問卷疆界合併(D10 改寫:不再抽新套件 task_survey 作答層併入 jedi-survey 成問卷疆界套件 排後段因為它是合併不是抽取——不解核心環、也不擋別人,且問卷作答層與 flow_control 有牽連(任務帶問卷),等 4.2 定形後再併最省事 鐵證:兩條 DB 外鍵跨過套件邊界,原「抽獨立新套件」技術上不可行;2026-03 schema 搬遷已把作答表與問卷表放同 schema。合併後照 D6/D7 補殼
4.7 CM-1483 jedi-ai-dashboard AI 儀表板生成引擎(~30 檔) 收尾棒——資料源 registry 是全系統疆界的鏡子,等所有疆界都定形了才知道要對哪些套件宣告介面(4.B 已先把註冊機制換好) 零跨模組依賴;資料源 registry 深綁本產品 data API,抽引擎、資料源以 port 注入(原 D1 降觀望,D8 解凍收回)
待定序 未開卡 cloud_integration / feedback / setup Drive 整合(~72 檔)/意見回饋(~25 檔)/開通精靈(~12 檔) 三支併入第四階段排程時一起定順位(原文保留) cloud_integration:7 條 flow_engine/participant 線;feedback:斷 2 條 system_config 線即 A 級;setup:與安裝流程綁定深——三支併入第四階段排程時一起定順位
不抽 associations 純關聯表膠水(67 檔) 永不獨立成套件——每張關聯表跟著「擁有語意的那端」走,在第四階段過程中逐步溶解

終局選項(範圍縮減:2026-08-30 user 指示 flow_control 升格第四階段議程)

flow_control 拆出——移入第四階段議程(user 2026-08-30 指示;已確認指的是稽核執行業務層那 37 支 service/236 檔,非 flow_engine 的範本管理):不再等商業決策,Phase 4 規劃時與 P13 同席討論。拆法已定調(user 同日拍板):「先單純拆出、切分後議」——照 jedi-iam 驗證過的「先搬家、後裝修」路徑:第一步整包搬成套件(import 名不變、稽核業務邏輯原樣帶走、機械比對證明零行為改動),第二步「通用流程骨架 vs 稽核專屬業務」的切分等真實第二種流程(問卷審核等)要掛入時拿真需求當設計輸入再做——無第二消費者硬切必畫錯線。技術耦合:D12 已定 oscal → flow_control 單向依賴,OSCAL 疆界設計必須知道 flow_control 自己也會成為套件,否則拆完返工;排序(P12/P13 之前或之後)屆時拿依賴數據定,初步傾向 P12 之後(先解最粗的 participant 邊、搬家包袱最小)。

終局選項(仍等商業決策):project 平台化——產品本體抽套件、主專案變組裝殼。等第二個合規產品線出現再議。

另案追蹤(不屬本案範圍):RLS 覆蓋缺口——user_roles / user_tenants / user_org_units 三張授權關聯表未啟用 RLS(live DEV 實查確認),現靠「讀取都經過受 RLS 的 users/roles」間接保護;任何直查這三張表的新程式即為跨租戶洩漏風險。已另開獨立 Notion case 追蹤(D9 身分族盤點的附帶發現),不混入 FR-069。


8. 套件階層依賴圖(living,隨拍板更新)

🔴 本圖描述 D1–D16 拍板後的「目標架構」,不是現況——現況到目標的路徑見 §7 各階段章節。每次新決策改變套件版圖(合併定形、退役期滿刪除、查證翻案),本圖與下方狀態表同步更新,並在變更紀錄註記。決策編號引用以 §3 決策表為 canonical。

維護慣例:狀態表是維護主體(好 diff、好逐列更新),mermaid 圖是給人看全貌的輔助——改表必改圖,改圖必改表。

8.1 三層架構(實線=允許的直接依賴)

架構只有一條實線規則:疆界插件只准直接依賴 jedi-common(層 0);插件彼此絕不直接相依,插件間的協作一律經宿主(層 2)的接線盤走 port 注入(見 8.2)。

%%{init: {'theme':'base','themeVariables':{'primaryColor':'#E2F0F1','primaryTextColor':'#14201F','primaryBorderColor':'#0E7C86','secondaryColor':'#EEF2F3','secondaryTextColor':'#14201F','tertiaryColor':'#FBFCFC','tertiaryTextColor':'#14201F','lineColor':'#4A5A5C','textColor':'#14201F','mainBkg':'#E2F0F1','nodeBorder':'#0E7C86','nodeTextColor':'#14201F','edgeLabelBackground':'#FBFCFC','titleColor':'#14201F','clusterBkg':'#FBFCFC','clusterBorder':'#E4EAEB','actorBkg':'#E2F0F1','actorTextColor':'#14201F','actorBorder':'#0E7C86','actorLineColor':'#C7D1D2','signalColor':'#4A5A5C','signalTextColor':'#14201F','labelBoxBkgColor':'#EEF2F3','labelBoxBorderColor':'#C7D1D2','labelTextColor':'#14201F','loopTextColor':'#14201F','noteBkgColor':'#F6EBD5','noteTextColor':'#14201F','noteBorderColor':'#9C6B12','activationBkgColor':'#EEF2F3','activationBorderColor':'#C7D1D2','sequenceNumberColor':'#FFFFFF'}}}%%
flowchart TB
    subgraph L2["層 2 宿主/產品(接線盤)"]
        HOST["Guidant AI 主專案<br/>核心業務(flow_control/OSCAL 應用層)<br/>+各插件 adapter 接線+資源域授權"]
    end

    subgraph L1["層 1 疆界插件(彼此不直接相依)"]
        direction TB
        subgraph L1A["身分與基礎服務"]
            IDENTITY["jedi-iam<br/>(2.5 階段成形:auth+login<br/>+mfa+captcha+身分中介層)"]
            NOTIF["jedi-notification"]
            FILEUP["jedi-file-upload"]
        end
        subgraph L1B["第一階段五支(已發版)"]
            AIBOT["jedi-ai-bot"]
            INTEG["jedi-integrity"]
            LOGFWD["jedi-log-forwarding"]
            RAGENT["jedi-remote-agent"]
            LICRT["jedi-license-runtime"]
        end
        subgraph L1C["疆界重劃中(第四階段定形)"]
            SURVEY["jedi-survey-suite(暫名)<br/>survey+作答層(D10)"]
            DETECT["jedi-detection<br/>不含 device(D11)"]
            OSCALV2["jedi-oscal-v2 系<br/>(D12 查證後定形)"]
        end
        subgraph L1D["獨立補殼者(第三階段)"]
            OTHERS["jedi-device/jedi-bulletin/jedi-issue<br/>jedi-system-config/jedi-system-menu<br/>jedi-information-system/jedi-project<br/>jedi-flow-engine/jedi-log(存活半)"]
        end
    end

    subgraph L0["層 0 地基(唯一允許被直接依賴)"]
        COMMON["jedi-common<br/>session/查詢基底(含 JSONB)/例外<br/>身分脈絡包介面/SessionMixin"]
    end

    HOST --> L1
    L1A --> COMMON
    L1B --> COMMON
    L1C --> COMMON
    L1D --> COMMON
圖 1 — 套件三層架構(目標態):層 1 插件彼此零直接依賴,全部只踩層 0 地基

退役中(D13,標 deprecated 觀察一版後刪):jedi-oscal(v1)、jedi-resource-storejedi_system_log(jedi-log 的壞半)。已下架:jedi-department(org_units 重複概念)。這四支不入圖。

8.2 Port 接線(虛線=介面宣告,宿主注入實作)

D16 通則的四張標準 port:插件宣告需要什麼形狀的服務,宿主接線時把提供方的實作(包成 adapter)注入——提供方與消費方互不知道對方存在。

%%{init: {'theme':'base','themeVariables':{'primaryColor':'#E2F0F1','primaryTextColor':'#14201F','primaryBorderColor':'#0E7C86','secondaryColor':'#EEF2F3','secondaryTextColor':'#14201F','tertiaryColor':'#FBFCFC','tertiaryTextColor':'#14201F','lineColor':'#4A5A5C','textColor':'#14201F','mainBkg':'#E2F0F1','nodeBorder':'#0E7C86','nodeTextColor':'#14201F','edgeLabelBackground':'#FBFCFC','titleColor':'#14201F','clusterBkg':'#FBFCFC','clusterBorder':'#E4EAEB','actorBkg':'#E2F0F1','actorTextColor':'#14201F','actorBorder':'#0E7C86','actorLineColor':'#C7D1D2','signalColor':'#4A5A5C','signalTextColor':'#14201F','labelBoxBkgColor':'#EEF2F3','labelBoxBorderColor':'#C7D1D2','labelTextColor':'#14201F','loopTextColor':'#14201F','noteBkgColor':'#F6EBD5','noteTextColor':'#14201F','noteBorderColor':'#9C6B12','activationBkgColor':'#EEF2F3','activationBorderColor':'#C7D1D2','sequenceNumberColor':'#FFFFFF'}}}%%
flowchart LR
    PLUGINS["任一疆界插件<br/>(bulletin/license-runtime/<br/>log-forwarding/survey-suite …)"]
    HOST["宿主接線盤<br/>(register 時注入 adapters)"]
    IDENTITY["jedi-iam"]
    NOTIF["jedi-notification"]
    FILEUP["jedi-file-upload"]
    SYSCONF["jedi-system-config"]

    PLUGINS -. "①身分名冊 port<br/>(user/tenant/org 三名冊)" .-> HOST
    PLUGINS -. "②INotifier port" .-> HOST
    PLUGINS -. "③檔案存取 port" .-> HOST
    PLUGINS -. "④設定讀取 port" .-> HOST
    HOST -. 注入 adapter .-> IDENTITY
    HOST -. 注入 adapter .-> NOTIF
    HOST -. 注入 adapter .-> FILEUP
    HOST -. 注入 adapter .-> SYSCONF
圖 2 — 四張標準 port 的接線方向:插件宣告(虛線出)、宿主注入、服務方提供(虛線入)

8.3 逐套件狀態表(維護主體)

套件 層級 狀態 決策編號
jedi-common 0 地基 已發版 0.0.32(P7 擴充:JSONB 查詢/身分脈絡包/SessionMixin 正名) D4、D16、正名案
jedi-iam(原暫名 jedi-identity) 1 合併中(2.5 階段:.13/.14/.15/.16/.17 已收;改名棒 CM-1464 已執行完畢,餘 .18 收口發版) D9
jedi-notification 1 待補殼(維持獨立——12 消費點多與身分無關) D9、D16
jedi-file-upload 1 待補殼(維持獨立——jedi-issue 為第二消費者) 疆界地圖①
jedi-ai-bot 1 已發版 0.0.1(插件契約首例) D6、D7
jedi-integrity 1 已發版 0.0.1 D6、D7
jedi-log-forwarding 1 已發版 0.0.1 D6、D7
jedi-remote-agent 1 已發版 0.0.1(migration 隨包首例;機器身分不併 identity) D6、D7、D9
jedi-license-runtime 1 已發版 0.0.1(驗證核心;執法留宿主) D6、D7
jedi-survey-suite(暫名) 1 待合併(第四階段:jedi-survey+主專案作答層,跨邊界 FK 鐵證) D10
jedi-detection 1 待抽取(第四階段 P9,不含 device) D11
jedi-oscal-v2 系 1 待定形(第四階段 P13——真三角第三邊為 flow_control,開工前先派查證棒) D12
jedi-device 1 待補殼(獨立——歸資產盤點語境,非檢測) D11
jedi-bulletin 1 待補殼(維持獨立套件——user 定案可拔往其他產品;名冊/通知依賴走 port 化) D14、D16
jedi-issue 1 待補殼(死碼去留「待另議」——boundary-map 原 D16 項) 疆界地圖⑤
jedi-system-config 1 待補殼
jedi-system-menu 1 待補殼(輕量——與 ui_routes 無重複,已查證)
jedi-information-system 1 待補殼(輕量;FR-032 G 抽取先例) D4
jedi-project 1 待補殼(凍結與否「待另議」——boundary-map 原 D15 項;project_extensions 收斂會動它,見 CM-1449) D15-①
jedi-flow-engine 1 待補殼(P12 participant 抽出後評估殼內邏輯併回) 凍結路線圖
jedi-log(存活半) 1 待拆兩半(API 存取紀錄 10 萬筆活資料留;jedi_system_log 壞半退役) D13
jedi-oscal(v1) 退役中(deprecated 觀察一版;順帶消 AGPL 依賴) D13
jedi-resource-store 已退役(2026-08-30 user 拍板即刻執行:主專案 pin 已拔、deprecated 標記完成;實體下架待觀察期) D13
jedi_system_log 退役中(一載入即炸——與 jedi-common 表衝突) D13
jedi-department 已退役(2026-08-30 user 拍板即刻執行:主專案註解殘行已清、deprecated 標記完成;實體下架待觀察期) D9 清理項/D13 追加
jedi-login/jedi-mfa/jedi-captcha 併入 jedi-iam 後消失(舊名留轉發過渡) D9

9. 端到端驗收(第一階段全案收口判準)

  1. 六支新套件(ai-bot / integrity / log-forwarding / remote-agent / license-runtime)上 Nexus,主專案 pyproject.toml== pin;jedi-common、jedi-auth 各完成一波擴充發版。
  2. 主專案淨減約 220 檔;common/ 只剩資源域 authz、業務工具與真正的主專案膠水。
  3. 守衛測試全綠:每支套件源碼 grep 0 處主專案 import;common/ 反向 import 0 條。
  4. BE 全功能手測清單過(AI 聊天、防篡改 gate、log 轉發、agent 心跳派工、license 啟用、四角色權限、檔案上傳)。
  5. 六支新套件全部通過拔掉測試(D6):逐支註解 app_modules.py 註冊行 → BE 正常啟動、該模組路由/選單消失、其餘功能不受影響。 5b. 六支新套件 harness CI 全綠+接入 README 齊備(D7):每支套件 standalone harness 可獨立起、套件測試在 harness 內全綠並掛上 CI;接入 README(port 清單/註冊行/migration 套法/quickstart)齊備且 quickstart 實走過。
  6. docs/claude/jedi-packages.md 補齊六支新套件段落(並順帶補上既有未登記的 13 支)。
  7. monorepo 各套件 repo 側 commit 完成(push 與發版時點依鐵則等 user 明示)。