本卡屬 FR-095(母卡見本 arc README front matter),第 7 棒 P5:專案 CRUD+人員指派剩餘領域層(jedi 套件 repo)。只掃不修。
套件的 project 子模組全部(專案的資料存取:entity、repo、service、model,13 檔,沒有對外 API)+ participant 子模組還沒進 P2 的領域層(五種參與者的 entity、query entity、repository interface、domain service,24 檔)。共 37 檔(排除 0 行的 __init__.py)。只找問題、不修問題。
收尾棒。projects 是這支套件唯一帶租戶欄的表,套件 migration 說「租戶隔離由專案層擋」——這一棒就是驗證這句話:專案層的查詢與 domain service 到底有沒有擋、擋的是租戶還是專案、以及五種參與者的 domain service 在「查一筆」「查全部」時有沒有強制帶專案條件。跑完這棒才能宣稱「jedi-task-platform 掃過了」。
這些是首腦讀過程式碼後認為最容易出事的地方,是思考起點不是檢查清單。每條後面的「首腦核對」是首腦親自開檔的結果——✅ 屬實的不必重做核對,直接當錨點追下去;標「待 runner 核對」的才要你自己開檔確認。工具沒答的自己開檔查了再寫,標明「(工具未報,人工查證)」:
project/domain/service/project_domain_service.py(56 行)、project/infra/repository/project_repo_impl.py(19 行)、project/infra/model/project.py(102 行)——查專案時有沒有帶租戶條件?還是完全靠資料庫 RLS(而 RLS 是關的,總表第 43 條)?get_by_uid 拿到別租戶的專案會不會直接回?這是本棒最重要的一問,工具未報也要人工答。get_all/get_one:participant/domain/service/*_domain_service.py 五支——query entity 全部欄位為空時是回全表還是拒絕?project_participant_domain_service.py(55 行,最大的一支)有沒有 validate_* 方法是「查無就過」。與 P2 的 repo 層對照(P2 查 SQL、本棒查 domain 邏輯)。participant/domain/entity/*_query_entity.py 五支——若 project_id 是 Optional 且沒有任何一層強制,「不帶 project_id」就是跨專案查詢的合法輸入。project/app/dto/project_dto.py(47 行)——回應裡有沒有 tenant_id、建立者 login_name 等不該給前端的欄位。總表 §2.9 🅴 組同型。project/app/service/project_service.py(53 行):套件的專案 service 有沒有守門、宿主有沒有用它(宿主自己有一支 1,000+ 行的 app/flow_control/service/project_service.py,H1 掃)——若宿主整支重寫沒用套件這支,記「宿主零取用」(FR-088 P2 同型陷阱)。participant/domain/repository/*.py、project/domain/repository/project.py——interface 有沒有定義「不帶範圍的全表查詢」方法(例如 list_all()),有的話誰在用。授權判定怎麼流(首腦 2026-09-14 開檔核對,行號可直接打開):
common/authz/project.py(120 行):assert_project_manager :16-30/assert_project_role_fallback :33-57/assert_project_role :60-98/assert_project_participant :101-120。守門函式本身沒有 fail-open(fail-open 就是「查不到就放行」的壞習慣):查不到角色就 raise、沒有拿租戶代替專案、沒有 super_admin 短路。participant/app/service/participant_role_service.py:33-83,三層往上找:project_control_participants → control_group_participants → project_participants → 都沒有就回 None。core/plugins/participant.py:90-102 的 adapter → 套件 participant/common/guard.py:26-52 的 configure();沒接線時 :45-49 直接 raise、不放行(這一段是好的)。task 那一半的三道守門(license/project_role/identity)在 core/plugins/task.py:89-98,與 jedi-compliance-audit 共用同一組 adapter。participant/api/guards.py:10-12 的 CAPABILITIES 是空 tuple,入口只有宿主注入的 jwt_required(只驗「你有登入」)。