本卡屬 FR-091(母卡 CM-1690),能力點前置三卡的第二張。等 CM-<asset 定形卡> commit 進 jedi repo 後才派(照它的形狀抄)。動四支套件;survey 那支順帶改守門寫法。建議 model:Sonnet 5,effort:medium——形狀已定,是照抄加一次守門改寫,錯誤會被凍結集合與 pytest 抓到。
上一張卡(asset 定形)定了「套件把自己需要的能力點列成 CAPABILITIES 清單」的形狀。這張把已經整理完、沒人在動的四支套件補上同樣的清單。其中三支(bulletin/system-core/notification)已經是 asset 的守門形狀(route 從 config 取名字、guards.py 有 capability_required),只要加清單、常數改從清單取,半小時一支。
survey 不一樣:它的 route 直接 from jedi_iam.authz import require_capability 然後 @require_capability("survey.create") 寫死字串,23 處。而且 guards.py 檔頭有一段設計說明,明寫「capability 屬身分疆界、實體在 jedi_iam.authz,直接 import 套件,不 port 化」——這是前一棒刻意的決定,跟 asset 的形狀矛盾。決策者 2026-09-13 裁:全部收成 config 形狀,理由是換一個沒有 jedi-iam 的宿主也要能掛問卷,而且主專案守門實作要換時只能有一個落點(core/plugins/_host.py 的 host_defaults)。這張卡要把 survey 改過來,並把那段說明改成新的理由。
jedi-survey/jedi_survey/api/routes/survey_route.py(import 在 :12,用在 :107、:135、:158、:177、:246、:267、:290、:304 等)與 survey_question_route.py(:34、:63、:99、:114、:135)。名字只有三個:survey.create(11 處)、survey.update(6 處)、survey.delete(6 處)。SurveyAdapters(plugin/contract.py)目前沒有 capability_required 欄位;auth_required 有但 CM-1716 回寫說零消費端。本卡加 capability_required,且 _assert_wiring 要把它列為必填(缺了拒絕掛載,理由同 asset)。主專案側 core/plugins/survey.py 已透過 host_defaults() 填三件守門,加欄位後不用改主專案——runner 要實跑確認 host_defaults 真的有 capability_required 這個 key(core/plugins/_host.py:87-91)。bulletin-list.read(bulletin 的第二個資源)。要不要列進 bulletin 的清單:列,判準是「這個名字的資源歸這支套件管」。poetry update,不 commit)。jedi-asset/jedi_asset/plugin/contract.py 的 CAPABILITIES 段、tests/unittest/test_plugin_layout.py 新加的三條測試、jedi_common/plugin/capability.py。照抄,不要自創變體。__all__ 加 CAPABILITIES;版面守衛 FROZEN_PUBLIC_SYMBOLS 加一項;加凍結集合+id 比對兩條測試。README 一句話。SurveyPluginConfig 加三個欄位;② SurveyAdapters 加 capability_required,_assert_wiring 列必填;③ guards.py 加 capability_required(getter) 函式(形狀抄 asset guards.py:39-55);④ 兩支 route 檔 23 處改成 @capability_required(lambda rt: rt.config.survey_create_capability),拔掉 from jedi_iam.authz import require_capability(同一行的 issue_signed_token、signed_token_required 屬軸⑤ signed-token,保留,那個決策沒改);⑤ 改寫 guards.py 檔頭說明。注意 decorator 順序:asset 的 capability_required 在 request 期才解析 config,所以掛在 class method 上的順序與原本 require_capability 相同即可,但 runner 要實跑一條 403 確認守門真的還在。SurveyAdapters 缺 capability_required 時 register(mount_api=True) 要拋錯(照 asset 的 _assert_api_wiring 測試)。突變:把 _assert_wiring 的必填清單拿掉 capability_required → 這條紅。