本卡屬 FR-155(母卡 CM-2977 https://app.notion.com/p/FR-155-RBAC-tab-4-11-400346da4cd081c1b7ffce63ec77390d),第 5 批 T-5.1:驗收時累積、決策者 2026-10-22 裁示的後端改動,一張做完。等 T-5.0 合回後在 feature/FR-139 做。
前 11 張卡做完後有一批「要決策者決定」的事,決策者已全部裁示。這一棒把後端那幾件一次做掉:兩個沒有任何程式讀的能力點拿掉;列表上「負責人」欄改成看「預設負責人」這個角色而不是看能力點;流程站沒填主責時進站通知改成跟推進判定一樣退回站預設;三個現存的權限破口補守門;流程設計器存檔只接受三個跟推進有關的能力點;加兩個小修正。
proj.stage.advance、proj.job.execute:新 migration 2026-10-xx-fr155-drop-two-unused-capabilities.sql(主線 active):先 DELETE FROM role_capability_patterns WHERE pattern IN (...),再 DELETE FROM capabilities WHERE name IN (...),結尾斷言兩表 0 列。同步改:scripts/sql/2026-10-21-fr155-project-roles-schema.sql 不動(已套過的 migration 不回改);scripts/sql/2026-10-21-fr155-seed-project-roles.sql 的四個 ARRAY 拿掉這兩個(新租戶照新清單);resources/roles/project-roles.json 拿掉;test/_project_role_fakes.py、test/flow_engine/test_resolve_main_caps.py:42-43 改用別的能力點;scripts/deliverables/gen_permission_matrix.py 重跑產 FE 常數檔(FE 那支由 T-5.2 commit)。回寫明講「出貨基線待重產」。infra/readmodel/audit/audit_plan_list_query.py:33,224,325 與 closing_report_list_query.py:26,141 的 MANAGER_CAPABILITY → 改查「該租戶 kind='project' AND is_default_owner 的角色 id」(infra/readmodel/project_role_capability_query.py 加一支 default_owner_role_id(tenant_id),有快取);稽核員名字欄(audit_plan_list_query.py 的 auditors)改「有 proj.audit.judge 且 project_role_id != 預設負責人 id」。app/flow_engine/service/stage_entered_notify_service.py:52-55 main_caps 空時改用 stage_object.default_main_roles(照 stage_advance_service.py:668-672 _resolve_main_caps 同一寫法;把那支搬到 stage_entered_recipients.py 成純函式共用,不要複製第二份)。需要 stage_object:看 caller 有沒有帶,沒有就用 stage_object_code 查(StageObjectDomainService)。proj.job.manage」:app/flow_engine/service/job_evidence_service.py:98(add)、:165(update)、:191(delete) 三處 assert_project_participant → 改走 app/flow_engine/service/job_operator_guard.py::assert_job_operator_by_workflow_execution_id(wf_service, workflow_execution_id, template_job_id)(既有,內部就是被指派人 ∪ proj.job.manage)。template_job_id 從 job_execution.template_job_id 取。讀取類(:62、:83)不動。proj.report.manage:app/project_summary_report/service/project_summary_report_history_service.py:69 revert_data_from_cruise_project_report_history 的守門從 _require_participant 改 assert_project_capability("proj.report.manage", self._participant_role_service, project_id, not_found_code=GRC_SUMMARY_REPORT_NOT_FOUND);兩支讀取(:46、:56)不動。core/plugins/evidence_classification.py:83-96 is_any_project_manager 改成 viewer_has_capability("evidence.classification.update")(from common.authz import viewer_has_capability,軸④)。套件 port 名字不改(套件不動)。拿掉那段讀舊 role 欄的查詢與 ParticipantRole import;從 T-1.1 守衛白名單拿掉這個檔。app/flow_engine/service/main_role_check.py 加常數 MAIN_ROLE_ALLOWED = ("proj.review.approve", "proj.audit.judge", "proj.stage.advance-any");assert_main_roles_are_project_capabilities(設計器 strict 入口)改成「不在 MAIN_ROLE_ALLOWED 就擋」,錯誤訊息列出允許的三個;專案實例存檔入口(upgrade_legacy_main_roles 後那條)維持「是專案能力點即可」(舊實例可能存別的)。stage_objects.default_main_roles 六站已在三個內,不動。participant/common/project_role_catalog.py:29 resolve_for_write 路徑(POST/PUT /project-participant)補「角色屬專案所在租戶」檢查:沿用 BE app/flow_control/service/project_participant_sync.py:51 assert_roles_belong_to_tenant 的判法;套件層沒有那支就透過既有 port 注入(看 participant/domain/ports.py:137 那個 port 怎麼接),不要在套件內複製一份。走 path dependency。app/auth/service/project_role_rules.py:29 apply_default_owner 設預設負責人又停用時,改拋 PreconditionFailedError(FlowControlErrorCode.GRC_412078)(碼不變,例外類別對齊 412 段)。select count(*) from capabilities where module='proj' = 13;select count(*) from role_capability_patterns where pattern in ('proj.stage.advance','proj.job.execute') = 0。proj.participant.manage)後不出現在負責人欄。main_role 清空、起專案推進到該站:進站通知收件人=站預設能力點的人(看 log/app.log)。