本卡屬 FR-089(母卡 CM-1688),修 arc review CM-1738 的 C1 與 C2,Critical。建議 model:Sonnet 5,effort:medium——修法明確,重點在把守衛推廣到六支並用突變證明它抓得到這種錯。
C1:系統選單管理頁的新增、修改、刪除三個按鈕,root 租戶管理員按下去一律 500。原因是 CM-1699 把 ctx 機械改名成 rt 時,三行守門 @capability_required(lambda c: rt.config.xxx) 只改了裡面的變數、沒改參數名,rt 在那個位置不存在。測試全綠、服務起得來、一般使用者被平台管理員守門先擋掉看不到,所以沒人發現。首腦本機 DEV 實打三端點全 500、log 三筆 NameError: name 'rt' is not defined;全 21 支 42 處 lambda 只有這 3 處錯。
C2:四處程式碼註解寫「兩處的值必須一致,由測試 X 焊死」,但那四個測試檔在兩個 repo 都不存在(首腦 find 零命中)。假守衛比沒守衛危險——讀者會因為相信有保護而放心只改一邊。最實害的一條:DETECTION_TOOL_JOB_TYPE = "detection_tool" 在套件與主專案各一份,主專案兩支測試都只 import 主專案那份,沒有任何地方比對套件那份。
jedi monorepo ~/Projects/Jedicogy/module/jedi-python-package
jedi-system-core/jedi_system_core/api/routes/system_menu_route.py:92,112,124 lambda c: rt.config.menu_{create,update,delete}_capability
jedi-detection/tests/test_plugin_layout.py:224 test_routes_take_capability_names_from_config_not_literals(唯一有 AST 守衛的一支,但只驗形狀不驗參數名)
jedi-detection/jedi_detection/app/service/detection_job_binding_handler.py:64 註解指 test_cm1493_detection_handler_moved.py(不存在)
jedi-detection/jedi_detection/infra/detection_execution/repository/detection_execution_repo_impl.py:13 註解指 test_detection_execution_timeout.py(不存在)
jedi-iam/tests/test_plugin_contract.py:6 註解指 test_boundary_mutation.py(不存在)
jedi-iam/tests/test_role_route_capability.py:6 註解指 test_role_mapper_list_omits_users.py(不存在)
jedi-system-core/harness/dev_app.py:277 smoke() 只打 /system/menu/<group> 與 /system/menus,沒打 /system-menu 三條
BE ~/Projects/Billows/Audit-Manager/compliance-manager-be
app/detection_tools/task_type_declaration.py:37 DETECTION_TOOL_JOB_TYPE 主專案那份
test/test_grc_job_detection_type.py、test/test_cm1658_my_job_type_no_downgrade.py 只 import 主專案那份
lambda c: 改 lambda rt:,其他不動。test_routes_take_capability_names_from_config_not_literals 複製到另外五支有 capability_required(lambda ...) 的套件(asset/bulletin/survey/notification/system-core,各放 tests/unittest/test_plugin_layout.py 或既有版面守衛檔),並在六支都加一條判定:arg.args.args and arg.body.value.value.id == arg.args.args[0].arg(lambda 參數名必須等於 body 裡取 .config 的那個名字)。先查再寫:六支既有的 test_plugin_layout.py 長什麼樣,沿用它的 helper 與檔案掃描方式,不另寫一套 AST 走訪。POST /api/1.0/system-menu 帶 X-Auth+X-Platform-Admin header,斷言不是 500(400 或 200 都算過)。看 harness/dev_app.py:277-300 既有 smoke 怎麼帶 header 照做。git log --all --diff-filter=D -- '*<檔名>' 確認是「被刪」還是「從沒寫」。detection 常數那條:在 BE test/ 補一支真的比對兩處常數的測試(from jedi_detection.app.service.detection_job_binding_handler import DETECTION_TOOL_JOB_TYPE as PKG、from app.detection_tools.task_type_declaration import DETECTION_TOOL_JOB_TYPE as HOST、assert PKG == HOST),註解改指那支新測試。其餘三條若查無原測試:把「由測試 X 焊死」那句拿掉,改成一句陷阱描述(「兩處值必須一致,改一邊不改另一邊症狀是 X」);若原測試存在於 git history 且仍有意義,還原它。lambda c: rt.config... → 該支新守衛要紅。還原。lambda rt: "plugin.update" → 既有守衛要紅(確認推廣時沒弄壞原判定)。還原。"detection_tools" → 紅。還原。git diff --stat 確認真的改到檔。全量:六支套件各自 tests/ 全跑貼 tail -1(在自己 commit 的 worktree、PYTHONPATH 只指樹);BE pytest test/test_module_boundaries.py test/test_grc_job_detection_type.py <新測試> -q。
POST /api/1.0/system-menu body {} → 應回 400(body 驗證)不是 500;PUT/DELETE /api/1.0/system-menu/1 同理回 4xx 非 500。tail log/app.log 零 NameError。cd jedi-system-core && docker compose -f harness/docker-compose.yml up -d && <BE venv python> harness/dev_app.py --smoke && docker compose -f harness/docker-compose.yml down -v,新加那條 smoke 過。