# FR-190 Agent 主控台權限能力點化 — 收尾總結（2026-11-10）

> 兩天完成：2026-11-09 需求、討論稿四頁雛形、D1～D9 裁定、design v1.0、14 張卡一次開完；11-10 工作坊跑完七批、首腦總驗、四 repo 合回、出貨基線重產、決策者裁收尾。
> 規格看 `docs/spec-site/current/evidence/agent-console.md` §3、`remote-agent-manage.md`、`system-admin/access-role-detail.md` §4.2；操作看 `docs/user-manual/agent/13-standalone-operation.md`「角色權限：26 項」。

## 一、做了什麼（白話）

Agent 主控台的權限原本只有 7 個大範圍：一個「設定」包 9 個頁面、一個「下載」包 5 種檔、看與執行不分、主系統派下來的掃描紀錄要有「設定」權限才看得到。管理員做不到「可以下載掃描報告但不能下載證據檔」「只管 LDAP 不碰工具帳密」。

現在拆成 **11 個功能 × 檢視／設定／執行／下載，共 26 顆**，全部是主系統的能力點，角色設定頁「Agent」大組底下的「Agent 主控台」子頁逐顆勾。使用者點「進入主控台」時主系統把他持有的顆寫進票，Agent 照票開頁面、擋 API；斷線用的離線操作者名單每次心跳依當下持有的顆重算。這兩條同步機制本來就有，本案只換了顆粒。

三件順手補的：主系統先升、Agent 還沒升時使用者照常登得進，頂部一句提醒（不再整張票拒收）；主系統派的掃描紀錄歸「掃描 · 檢視」；角色頁一顆「比照主系統功能帶入」鈕，有「檢測工具 · 修改」的角色一鍵帶出「工具設定 · 設定」，可再拔。

## 二、關鍵決策（終局）

| 決策 | 結論 |
|---|---|
| D1 顆粒 | 11 功能 × 四動作＝26 顆；動作是角色頁現成的詞 |
| **模組前綴（開卡後資安審查改向）** | **`agent.<功能>.<動作>`，不放 `detection`**。出貨 seed 稽核主管有 `detection.*.*`、稽核員／一般成員／唯讀有 `detection.*.read`，放 `detection` 底下新裝客戶的稽核主管升級後自動拿到全部 26 顆、唯讀拿到 11 顆檢視。FR-166 的 7 顆已踩在這洞上，本案一併補掉。DEV 沒有這些 pattern，runner 在 DEV 測不出來，守衛改掃 seed 檔本身 |
| D2 舊 Agent 收到不認得的範圍 | 丟掉、照常登入、頂部橫幅；全部不認得才 403 `TICKET_SCOPE_EMPTY` |
| D3 派工掃描紀錄 | 歸 `scan.read`／`scan.download`，不分來源 |
| D4 角色頁排法 | 角色樹第一層多「Agent」大組（`capabilities.module` 自動分組），底下「Agent 主控台」子頁（`ui_routes.tree_page`），26 顆依功能分組、標籤「功能 · 動作」、動作順序檢視→設定→執行→下載 |
| D5 舊 7 顆退場 | 字面持有者展開到新顆（含客戶自建角色，不過濾 system），刪舊顆與三張關聯表的列；`legacy_name` 記舊名 |
| D6 離線操作者不下放 | **只不下放 `update.read`、`update.execute`；重啟 `ops.execute` 下放**（推翻 FR-166 D14「重啟不下放」：斷線卡住要能現場重啟，重啟可逆、換版不可逆） |
| D7 主系統端點 | 代設帳密→`tools.update`；換發憑證→`keys.update`；重啟→`ops.execute`；補更新→`ops.update`；執行紀錄下載→`scan.download`／`netdiag.download` 依紀錄種類細判；簽票與清單可見→26 顆任一 |
| D8 票上寫法 | 原樣寫 26 個 `<功能>.<動作>` 字串（約 2.5 KB，上限 8 KB） |
| D9 跟主系統對應功能連動 | 不連動；等價的兩處（工具帳密、金鑰換發）守同一顆；其餘靠角色範本預帶（稽核員 `scan.read`＋`scan.download`）＋「比照帶入」鈕（protocol `MIRRORS` 15 條，一次性可再拔） |
| 三邊共用清單 | 放 `jedi-agent-protocol` 新模組 `console_scopes`（Agent 不裝 jedi-remote-agent，只裝 protocol，三邊都 import 得到的只有這裡）；jedi-remote-agent 三張表改推導、Agent `CONSOLE_SCOPES` 改 import、主系統 `_ADMIN_CAPABILITIES` 用 `capability_of()` |

## 三、改動範圍與 commits（四 repo 皆已合回 `feature/FR-172`，未 push）

| repo | 合併 commit | 內容 |
|---|---|---|
| jedi-python-package | `b98737d8` | protocol 0.6.0：`console_scopes.py`（26 顆、`OFFLINE_GRANTABLE` 24、`MIRRORS` 15、`scope_of`／`capability_of`）、`TICKET_SCOPE_EMPTY`、三邊鏡像測試；remote-agent 1.18.0：`contract.py` 三張表改推導、舊 7 顆退場。兩支已發 Nexus |
| BE | `654edf68b` | migration `2026-11-10-fr190-agent-console-capabilities.sql`（26 顆、子頁、展開、刪舊、稽核員預帶）；`_ADMIN_CAPABILITIES` 換顆、`_agent_local_runs.py` 依 kind 細判；`gen_permission_matrix` 加 Agent 端守門判定；`GET /roles/<uid>/agent-console-mirror`；守衛 `test_fr190_seed_patterns_exclude_agent_module.py`；改回釘版；SPEC 兩頁＋角色明細頁＋手冊 |
| Agent | `bee291e` | `shared/constants.py` 改 import 契約；`agent_auth.verify_console_ticket` 回 `(claims, dropped)`、全丟才拒；`/api/me` 回 `dropped_scopes`；68 條路由守門換顆、`runs_routes` 來源判斷收掉；`test_fr190_scope_table.py` 全 blueprint 對表；改回釘版 |
| FE | `f530c70c` | 主控台 `router.js` 與 13 個 view 換顆、`Shell.vue` 舊版橫幅、i18n；主站 `permission-tree.json` 加 `agent` 模組 26 顆、`ACTION_ORDER` 加 `download`、離線操作者標籤、Agent 管理頁按鈕換顆、`capabilities.js` 重產、`PermissionMenuTree.vue` 帶入鈕＋`useAgentConsoleMirror.js` |

**合回後追加**（FR-188 session，決策者直接指示）：FE `1d393861`「換發憑證」按鈕改掛 `agent.keys.update` 對齊後端；BE `5e4f5c4d6` 重產權限矩陣，`test_feature_capability_matches_backend_guard` 轉綠。

**出貨基線重產**：BE `a8583fe29`。188 基線庫先備份（`~/backup/guidant_ai_baseline_20261110_1630_before_FR190.dump`），套本案 migration，重產 `02／04／99`；本機乾淨 `postgres:16` 跑完整 `init.sh` 驗 26 顆／舊顆 0／子頁綁 26／marker 在／稽核員預帶 2／非系統角色萬用字元命中 `agent.*` 為 0。原本等基線的兩條守衛轉綠。

## 四、行為差異（升級客戶會看到什麼）

- 角色設定頁：「檢測 › Agent 管理」只剩 4 顆管理用；新「Agent」大組底下「Agent 主控台」子頁 26 顆；子頁標題列多「比照主系統功能帶入」鈕。
- 既有角色原本持有的 7 顆自動展開到對應新顆（例如原持「Agent 設定」→ 工具／LDAP／金鑰／授權／維運／連線六組的檢視＋設定 14 顆＋掃描檢視）。持 `download-files` 但沒 `configure` 的角色拿不到診斷包下載（與現況一致）。
- 主控台側欄只出現持有「檢視」的頁；下載鈕看「下載」顆；執行鈕看「執行」顆。
- 主系統升了、Agent 還是舊版：登得進，頂部橫幅「有 N 項權限尚未支援，升級 Agent 後生效」。
- 離線操作者多了重啟，少了換版（與 FR-166 相反）。
- **不相容**：新 Agent 不認舊主系統發的 7 個名字（丟掉後全空→403）。升級順序主系統先。

## 五、規範文件清單

| 文件 | 狀態 |
|---|---|
| `docs/spec-site/current/evidence/agent-console.md` §3 ＋ 變更紀錄 | ✅ |
| `docs/spec-site/current/evidence/remote-agent-manage.md` 按鈕守門、離線操作者欄 ＋ 變更紀錄 | ✅ |
| `docs/spec-site/current/system-admin/access-role-detail.md` §4.1 四支子頁、§4.2 26 顆與帶入鈕 ＋ 變更紀錄 | ✅（卡上寫 `role-manage.md`，runner 判斷角色設定頁實際 SPEC 是 FR-132 後的 `access-role-detail.md`，正確） |
| `docs/user-manual/agent/13-standalone-operation.md`「角色權限：26 項」表、舊版橫幅、檔案權限整台警示 | ✅ |
| `design.md` v1.0、`discussion.md`、`prototype/index.html`、`README.md` 三段 | ✅ |
| `docs/analysis/2026-11-10-agent-console-capability-granularity.md` | ✅ 本次收尾寫 |
| memory `feedback_capability_module_prefix_check_seed_wildcard_patterns` | ✅ 本次收尾寫 |
| 開卡範本硬規則 8「雛形只取結構」＋ memory `feedback_prototype_is_explainer_rewrite_all_copy_in_production` | ✅（開卡時已入） |

## 六、已知 follow-up

- **畫面手測**：角色頁子頁與帶入鈕、主控台側欄依權限顯示、舊版 Agent 橫幅——runner 全用測試碼驗，沒人實機點過。DEV 的 Agent 要重起到新版才看得到。
- **主線本來就紅的守衛**：`test_fr132_capability_home_route::test_dev_every_capability_has_a_home` 列 13 顆 `proj.*` 專案角色能力點沒 home，與本案無關；FR-188 另開 FR-194 處理全量矩陣紅。
- **push**：四 repo `feature/FR-172` 都有新 commit，推前 fetch。
- **STG／POC**：未上，等放行。升級順序主系統先、Agent 後（新 Agent 不認舊票）。
- **兩份系統說明過期，決策者裁先不補**：`docs/system-design/system-integration/03-身分與信任.md` 主控台票 `scope` 欄仍列舊 7 個範圍名；`docs/system-design/permission/` 權限說明書沒提 `module` 當第一層分組、`tree_page` 子頁、Agent 主控台 26 顆。下次動到任一份時一併更新。
- **`handoff/FR-190-STATE.md`／`LOG.md` 未開**：本案全程走工作坊、無跨 session 中繼，每棒紀錄在 Notion 子卡與本 SUMMARY。

## 七、教訓（進 memory 的那一條）

**新增能力點前先 grep 出貨 seed 的萬用字元 pattern**。能力點模組名不是命名風格問題，是授權範圍問題：`04-seed-core.sql` 的 `detection.*.*`／`detection.*.read` 讓任何放進 `detection` 的新顆自動送給四個系統角色，DEV 沒這些 pattern 所以測不出來。這次是開卡後的自動資安審查抓到，FR-166 已經漏過一次。
