---
title: "Agent 主控台權限能力點化 — 需求討論稿 (FR-190)"
brand: "Guidant AI · **FR-190** Agent 主控台權限能力點化"
eyebrow: "FR-190 · 需求討論稿 · 2026-11-09（v1 待審）"
h1: "Agent 主控台權限能力點化"
subtitle: "把 Agent 主控台 7 個大範圍拆成「每個功能 × 檢視／設定／執行／下載」26 顆能力點；主系統角色設定頁逐顆給；同步機制沿用、不重做"
lede: "Agent 主控台現在只有 **7 個權限範圍**，一個「設定」包了 9 個頁面、一個「下載」包了 5 種檔。管理員想讓某個角色「可以下載掃描報告、但不能下載證據檔」做不到，想讓人「只管 LDAP、不碰工具帳密」也做不到。本案把這 7 個範圍拆成 **11 個功能 × 最多 4 個動作＝26 顆能力點**，全部放進主系統既有的能力點表，角色設定頁逐顆勾；Agent 收到的票與離線名單照既有管道帶過去，**同步機制一行不改**。三邊（主系統、jedi-remote-agent、Agent）改成共用一份清單，不再各自硬寫。決策者已裁：**顆粒做滿 26 顆、舊 Agent 收到不認得的權限就丟掉而不是拒收、主系統派的掃描紀錄歸「掃描 · 檢視」**。"
chips: [
  {text: "已定：顆粒做滿 26 顆（D1）、不認得的權限丟掉不拒收（D2）、主系統派的掃描紀錄歸掃描檢視（D3）", kind: ok},
  {text: "待裁：D4 角色樹怎麼排、D5 舊顆怎麼退、D6 離線操作者不下放哪些、D7 主系統端點換哪顆、D8 票上怎麼寫、D9 要不要跟主系統對應功能連動", kind: warn},
  {text: "前作：FR-166／166.1 主控台與 7 個範圍、FR-169 下載加密、FR-172 Agent 更新、FR-181 長輪詢", kind: accent},
  {text: "雛形：prototype/index.html（四個畫面）", kind: accent}
]
footer: "FR-190 · Agent 主控台權限能力點化 — 需求討論稿 · 2026-11-09 v1 待審 · 現況來源：evidence-agent guidant_agent/console/api/*.py 約 60 條路由、jedi_remote_agent/plugin/contract.py、core/plugins/remote_agent.py、compliance-manager-fe console/router.js"
---

## 這案要解決什麼 {#why nav="為什麼"}

Agent 主控台是裝在客戶機器上的管理畫面。誰能進去、進去能做什麼，由主系統決定：使用者在主系統點「進入主控台」時，主系統看他持有哪些 Agent 能力點，把對應的「權限範圍」寫進一張五分鐘有效的入場券，Agent 驗票後照票上的範圍開頁面、擋 API。斷線時用的離線操作者名單，也是主系統每次心跳依該使用者當下的能力點算好下發。

**這套機制是對的，問題只在顆粒。** 現在只有 7 個範圍：

| 範圍 | 主系統能力點 | 實際蓋到的東西 |
|---|---|---|
| `configure` | Agent 設定 | 工具帳密、LDAP、金鑰換發、授權上傳、離線登入設定、Agent 名稱、主系統位址、儲存設定、連線與換主系統、三種「檢查更新」、診斷包、**主系統派的任務紀錄** |
| `files` | Agent 檔案 | 檔案列表、預覽、日誌頁 |
| `run-local-scan` | Agent 獨立掃描 | 掃描頁的看＋執行＋手動掃描紀錄 |
| `net-diag` | Agent 網路除錯 | 除錯頁的看＋執行＋除錯紀錄 |
| `download-files` | Agent 下載檔案 | 證據檔下載、掃描報告原檔、除錯報告、日誌匯出、診斷包 |
| `restart` | 重啟 Agent | 重啟 |
| `update` | 更新 Agent 版本 | 線上換版、離線上傳換版 |

::: {.callout .crit}
**🔴 三個做不到的事**

- 「可以下載掃描報告，但不能下載證據檔」——兩者同一顆 `download-files`。
- 「只管 LDAP，不碰工具帳密、不換金鑰、不換主系統」——九頁同一顆 `configure`。
- 「看得到掃描紀錄，但不能自己按執行」——看與執行同一顆。

而且 **主系統派下來的掃描紀錄要有「設定」權限才看得到**，有掃描權限的人反而看不到。原因只是當初沒有一顆對應的能力點，隨手掛在設定底下。
:::

另一個隱性問題：**範圍清單在三個地方各寫一份**——Agent 的 `CONSOLE_SCOPES`、jedi-remote-agent 的 `CONSOLE_SCOPE_CAPABILITIES`、主控台前端 `router.js` 每頁的 `scope`。三邊靠人工對齊，少一邊就是「票上有、Agent 不認」，整張票被拒。

## 分工概述（30 秒版） {#overview nav="分工概述"}

**整案一句話**：7 個範圍拆成 26 顆能力點，三邊改讀同一份清單，角色頁逐顆給，同步機制不動。

| 階段 | 做什麼 | 產出 | 完成怎麼判定（決策者檢查法） |
|---|---|---|---|
| **P0 契約** | 在三邊共用的 `jedi-agent-protocol` 套件寫下 26 顆的清單（功能、動作、顯示名、離線可不可下放） | 套件新版本 | 開套件檔看到 11 個功能 × 動作的表；三邊鏡像測試綠 |
| **P1 四邊接上** | 主系統 BE（能力點 migration、舊轉新、管理端點守門換顆、角色樹子頁）、主系統 FE（角色頁文案、離線操作者標籤）、jedi-remote-agent（宣告 26 顆、簽票、離線名單）、Agent 後端（約 60 條路由守門換顆、不認得的範圍丟掉）、主控台前端（選單與按鈕依新顆顯示、舊版橫幅） | 五個 repo 各一批 commit | **對照雛形第 1～4 頁**：角色頁看到「Agent 管理 › Agent 主控台」子頁底下 26 顆；給一個角色只勾「檔案 · 檢視」＋「掃描 · 下載」，用該角色進主控台：檔案頁只有預覽、掃描紀錄有下載鈕、其餘頁不出現 |
| **P2 收口** | 兩支套件發版、主系統與 Agent 改回釘版、Agent 出 image、SPEC 與手冊 | 版號、image、文件 | 用釘版 wheel 起主系統 HEAD 正常；手冊「角色權限」一節列 26 顆 |

**依賴**：P1 前要先開一張**環境卡**（主系統與 Agent 開發期改走本機路徑裝套件），否則 P1 的卡 import 到的是舊發行版、測試假綠。

::: {.callout .warn}
**測試前提：Agent 一定要升到新版**

26 顆新權限的守門寫在新版 Agent 裡，舊版 Agent 不認得新名字。要驗這個功能，測試用的 Agent 必須先裝新版。這點不管怎麼設計都一樣。D2 決定的是另一件事：**客戶現場還沒升的舊 Agent**，使用者是「完全登不進」還是「登得進但只有舊功能」。
:::

## 完整走一次：給稽核員「只能下載掃描報告」 {#usecase nav="走一次"}

1. 管理員在主系統「角色設定 › 稽核員」展開「檢測 › Agent 管理 › Agent 主控台」，勾 **掃描 · 檢視**、**掃描 · 下載**、**檔案 · 檢視**。不勾「檔案 · 下載」。
2. 稽核員在 Agent 管理頁點「進入主控台」。主系統逐顆查他持有的 26 顆，把持有的 3 顆寫進票。
3. Agent 驗票，3 顆都認得。側欄只出現「總覽、掃描、執行紀錄、檔案」。
4. 檔案頁：只有預覽鈕，沒有下載鈕。直接打下載 API 回 403。
5. 執行紀錄頁：手動掃描與主系統派的掃描都列出來（D3），每筆有「下載報告」鈕。網路除錯的紀錄不出現（沒有除錯 · 檢視）。
6. 管理員把稽核員加進這台 Agent 的離線操作者。下一次心跳，名單帶著同樣 3 顆下去。斷線時他用離線密碼登入，看到的畫面一樣。
7. 三個月後管理員把「掃描 · 下載」拿掉。他下次進主控台，下載鈕消失；離線名單下一次心跳跟著縮，已登入的 session 被踢。

```{.mermaid cap="圖 1 — 權限從主系統角色到 Agent 主控台的兩條路（都已存在，本案只改顆粒）"}
%%{init: {'theme':'base','themeVariables':{'primaryColor':'#E2F0F1','primaryTextColor':'#14201F','primaryBorderColor':'#0E7C86','secondaryColor':'#EEF2F3','secondaryTextColor':'#14201F','tertiaryColor':'#FBFCFC','tertiaryTextColor':'#14201F','lineColor':'#4A5A5C','textColor':'#14201F','mainBkg':'#E2F0F1','nodeBorder':'#0E7C86','nodeTextColor':'#14201F','edgeLabelBackground':'#FBFCFC','titleColor':'#14201F','clusterBkg':'#FBFCFC','clusterBorder':'#E4EAEB','actorBkg':'#E2F0F1','actorTextColor':'#14201F','actorBorder':'#0E7C86','actorLineColor':'#C7D1D2','signalColor':'#4A5A5C','signalTextColor':'#14201F','labelBoxBkgColor':'#EEF2F3','labelBoxBorderColor':'#C7D1D2','labelTextColor':'#14201F','loopTextColor':'#14201F','noteBkgColor':'#F6EBD5','noteTextColor':'#14201F','noteBorderColor':'#9C6B12','activationBkgColor':'#EEF2F3','activationBorderColor':'#C7D1D2','sequenceNumberColor':'#FFFFFF'}}}%%
sequenceDiagram
    participant Admin as 管理員
    participant Main as 主系統
    participant Agent as Agent
    participant User as 稽核員
    Admin->>Main: 角色設定頁勾 3 顆（掃描檢視／掃描下載／檔案檢視）
    User->>Main: Agent 管理頁點「進入主控台」
    Main->>Main: 逐顆查持有的能力點 → 票上寫 3 個範圍
    Main-->>User: 五分鐘票
    User->>Agent: 帶票登入
    Agent->>Agent: 認得的範圍留下、不認得的丟掉並記數（D2）
    Agent-->>User: 側欄只出現有「檢視」的頁；下載鈕看「下載」顆
    Note over Main,Agent: 離線路：每次心跳主系統重算該使用者的範圍 → 整份名單下發
    Main->>Agent: 心跳回應帶離線操作者名單（含 3 個範圍）
    Agent->>Agent: 覆蓋名單；縮權的人踢掉已登入 session
```

## 已經定案的 {#decided nav="已定案"}

::: {.callout .decided}
**D1 顆粒做滿：11 個功能 × 最多 4 個動作，共 26 顆**

動作只有四種，全部是角色頁已經認得的詞：**檢視**（頁面出現、唯讀 API）、**設定**（改這頁的設定）、**執行**（跑掃描、跑除錯、重啟、換版）、**下載**（把檔帶走）。

| 功能 | 檢視 | 設定 | 執行 | 下載 |
|---|---|---|---|---|
| 檔案 | 列表、預覽、上傳者清單 | | | 證據檔原檔 |
| 掃描 | 工具、目標、基準、紀錄（含主系統派的，D3） | | 執行、取消、重送結果 | 掃描報告原檔、工具 log |
| 網路除錯 | 目標、紀錄、預估、報告預覽 | | 執行、重送 | 除錯報告 |
| 日誌 | 查日誌 | | | 匯出日誌 |
| 工具設定 | 看已設定（不回密碼） | 改帳密、測試連線、清除 | | |
| LDAP | 看設定 | 改來源、改本機設定、測試、重新信任 | | |
| 金鑰 | 看金鑰狀態 | 換發 | | |
| 授權 | 看授權狀態 | 上傳授權檔、線上啟用 | | |
| 維運 | 服務狀態、離線登入設定、儲存設定 | 改名稱、改主系統位址、改儲存、改離線登入、三種「檢查更新」 | 重啟 | 診斷包 |
| 更新 | 看版本、檢查新版 | | 線上換版、離線上傳換版 | |
| 連線設定 | 看註冊狀態 | 註冊、探測、換主系統 | | |

**理由**：拆一半等於再做一次；四個動作是角色頁現成的欄，管理員不用學新東西。被排除：只拆下載那一顆（工作量三分之一，但「設定」包九頁的問題還在）。
:::

::: {.callout .decided}
**D2 舊 Agent 收到不認得的權限：丟掉，不拒收**

現況是票上有一個 Agent 不認得的範圍，整張票作廢、登不進。改成：**不認得的丟掉，認得的照常給**，主控台頂部顯示一句「這台 Agent 版本較舊，有 N 項權限尚未支援，升級後生效」。

**理由**：丟掉只會「少拿權限」不會「多拿」，安全上沒有風險；換來的是主系統可以先升、Agent 慢慢跟，現場不會因為漏一台 Agent 就整台登不進。被排除：維持拒收（升級順序變硬性、錯誤訊息只有一句「需要升級」）。

**影響**：Agent 的 `TicketScopeUnknown` 錯誤路徑拿掉；`/api/me` 多回「丟掉了幾個」給前端顯示橫幅；離線名單同樣過濾、不報錯（現況已是如此）。
:::

::: {.callout .decided}
**D3 主系統派下來的掃描紀錄歸「掃描 · 檢視」**

執行紀錄頁的掃描紀錄不分來源（本機手動、主系統派工）都歸「掃描 · 檢視」看、「掃描 · 下載」帶走報告。網路除錯紀錄歸「網路除錯 · 檢視／下載」。

**理由**：對使用者它們都是掃描結果，差別只在誰按的鈕，不該用兩顆權限管。被排除：維持掛在設定底下（只管帳密的人看得到所有派工結果，反而不合理）。
:::

## 待決策 {#decisions nav="待決策"}

::: {.callout .pending}
**D4 角色設定頁怎麼排這 26 顆**

現在 Agent 的 11 顆全部平鋪在「檢測 › Agent 管理」這一頁底下，與「新增／檢視／修改／刪除 Agent」四顆混在一起。26 顆再平鋪會是 30 個勾，看不懂。

角色樹已經支援「內頁當子頁」（FR-132 做的 `tree_page`）。三個排法：

- **A. 一個子頁「Agent 主控台」掛在 Agent 管理底下，26 顆放進去，標籤帶功能前綴**（「檔案 · 檢視」「檔案 · 下載」「掃描 · 執行」…），依功能排序。Agent 管理頁本身只留 4 顆管理用的。
- B. 11 個子頁，一個功能一頁，每頁 2～4 顆。樹更深，但一頁一功能最清楚。
- C. 維持平鋪（不做）。

[**建議**：A。一層子頁夠分清「管 Agent 清單」與「進主控台做事」，前綴讓 26 顆掃得過去；B 要為主系統沒有的 11 個畫面各造一列 `ui_routes`，太重。開卡前要驗：`ui_routes` 加一列 `is_menu=false、tree_page=true` 但主系統沒有對應畫面，前端路由守衛不會因此出錯。對照雛形第 1 頁。]{.rec}
:::

::: {.callout .pending}
**D5 舊 7 顆怎麼退場**

主系統能力點表現在有 7 顆舊的（`configure`、`browse-files`、`run-local-scan`、`net-diag`、`download-files`、`restart`、`upgrade`）。

- **A. migration 把舊顆的角色授權「展開」到新顆，然後刪掉舊顆**（含 `role_capabilities`、`route_capabilities`、`role_capability_patterns` 的列——這三張表對能力點沒有外鍵，要手清）。新顆的 `legacy_name` 記舊名。
- B. 舊顆留著、標退役不顯示。角色頁乾淨，但 DB 與矩陣產生器要多一個「退役」狀態。

**展開對照**（舊 → 新）：`configure` → 工具／LDAP／金鑰／授權／維運／連線六組的檢視＋設定，另加「掃描 · 檢視」（D3 後派工紀錄歸這裡）；`browse-files` → 檔案 · 檢視、日誌 · 檢視；`run-local-scan` → 掃描 · 檢視＋執行、日誌 · 檢視；`net-diag` → 除錯 · 檢視＋執行、日誌 · 檢視；`download-files` → 檔案／掃描／除錯／日誌四顆下載，**維運 · 下載只給同時持有 `configure` 的角色**（診斷包現況要兩顆都有）；`restart` → 維運 · 執行；`upgrade` → 更新 · 檢視＋執行。

[**建議**：A。出貨前無客戶、每版可直接升級由 migration 保證；留一堆退役顆是第二套真相。展開會讓少數角色「多一點」（持 `configure` 的多看到手動掃描紀錄）、「少一點」（持 `download-files` 但沒 `configure` 的拿不到診斷包，與現況一致）——都寫進 migration 檔頭。]{.rec}
:::

::: {.callout .pending}
**D6 離線操作者不下放哪些**

FR-166 定的：離線操作者不給「重啟」「換版」（不可逆、只給從主系統進來的人）。對到新顆就是 **維運 · 執行**、**更新 · 檢視**、**更新 · 執行** 不下放。

另外三顆要不要也不下放：**連線設定 · 設定**（註冊、換主系統——斷線時改主系統位址是「自救」還是「風險」？）、**金鑰 · 設定**（換發要連主系統，斷線時按了也沒用）、**維運 · 設定** 裡的「改主系統位址」。

[**建議**：維持 FR-166 的線，只不下放維運 · 執行與更新兩顆；其餘照使用者持有的下放。斷線時「換主系統位址」正是離線操作者存在的理由之一（FR-166 D14 主系統搬家）。清單上每顆加一個「離線可下放」旗標，放在共用清單裡，jedi-remote-agent 從旗標推導，不再另外手寫一張表。]{.rec}
:::

::: {.callout .pending}
**D7 主系統這邊也有幾個端點要換顆**

主系統「Agent 執行紀錄」頁的三個下載端點（報告原檔、報告檢視、工具 log）現在守 `download-files`；代設工具帳密守 `configure`；補更新基準守 `configure`；重啟守 `restart`。

[**建議**：執行紀錄下載**依紀錄種類**換成「掃描 · 下載」或「除錯 · 下載」；代設工具帳密 → 「工具設定 · 設定」；補更新基準 → 「維運 · 設定」；重啟 → 「維運 · 執行」；Agent 清單可見（`_AGENT_LIST`）改成「持有任一顆 Agent 主控台檢視」也看得到；簽票端點改成「持有 26 顆任一」。]{.rec}
:::

::: {.callout .pending}
**D8 票上怎麼寫 26 個範圍**

票是 RS256 JWT，現在 7 個範圍約 1.8 KB，Agent 登入入口的 body 上限 8 KB。

- **A. 原樣寫 26 個字串**（`files.download`），估 2.5 KB，Agent 端 `require_session("files.download")` 一對一，不需要任何對照表。
- B. 縮寫或位元編碼，票小但多一層解碼、除錯時看不懂。

[**建議**：A。8 KB 餘裕夠，可讀性在除錯時值錢。]{.rec}
:::

::: {.callout .pending}
**D9 要不要跟主系統的對應功能連動（決策者 2026-11-09 問）**

管理員的痛點是「主系統勾了掃描設定，Agent 這邊還要再勾一次」。三個做法：

- A. **自動跟**：持有主系統 `detection.profile.update` 就自動有「掃描 · 執行」。管理員只勾一次。
- **B. 不連動，但一次給**：角色範本出貨預帶對應顆；「Agent 主控台」子頁標題列放一顆「比照主系統功能帶入」鈕，按了把對應顆勾起來、管理員可再拔。兩處真正等價的（工具帳密、金鑰換發）D7 直接改守同一顆。
- C. 什麼都不做，26 顆全部手勾。

對照表（主系統功能 ↔ Agent 主控台功能）：

| Agent 主控台功能 | 主系統對應能力點 | 關係 | 出貨預帶給 |
|---|---|---|---|
| 掃描 · 檢視／執行／下載 | `detection.profile.*`、`detection.scan-zone.*`、`grc.job.*` | 只相關：主系統定義基準與目標、派任務；Agent 在機器上跑 | 稽核員：檢視＋下載；IT Manager：三顆 |
| 工具設定 · 檢視／設定 | `detection.plugin.*`；主系統「Agent 掃描工具設定」頁現守 `configure` | **等價**：代設帳密＝在主控台改帳密 → D7 該頁改守「工具設定 · 設定」 | IT Manager |
| LDAP · 檢視／設定 | `system.ldap-config.*` | 只相關：主系統 LDAP 是全租戶登入、Agent LDAP 是那台離線登入 | IT Manager |
| 授權 · 檢視／設定 | `platform.license.*` | 只相關：平台層 vs 每台一份 | IT Manager |
| 更新 · 檢視／執行 | `system.product-update.*` | 只相關：各自不可逆（FR-172） | 只給 Administrator |
| 維運 · 四顆 | `system.storage-config.*`、現有 `remote-agent.restart` | 儲存只相關（MinIO vs 本機路徑）；重啟等價於現有顆 | IT Manager；執行只給 Administrator |
| 日誌 · 檢視／下載 | 無（主系統日誌頁無獨立能力點；`log-forwarding` 是轉送設定） | 無對應 | IT Manager |
| 檔案 · 檢視／下載 | `grc.job-evidence.download` | 只相關：主系統按專案守、Agent 是這台全部不分專案（FR-166 刻意分開） | 不預帶（延續 FR-166.1 零角色） |
| 網路除錯 · 三顆 | 無 | 無 | IT Manager |
| 金鑰 · 檢視／設定 | `detection.remote-agent.update`（主系統換發憑證端點現守這顆） | **等價** → D7 改守「金鑰 · 設定」 | IT Manager |
| 連線設定 · 檢視／設定 | `detection.remote-agent.create`（註冊碼） | 相關：同一流程兩端 | IT Manager |

[**建議**：B。A 會讓風險面不同的兩件事綁死——能編全租戶基準的顧問不該因此能在客戶機器上開掃描，現場 IT 能跑掃描也不該因此能改基準；主系統現有 Agent 顆本來就獨立於其他功能，沿用。C 是現況痛點。B 的「比照帶入」對照表就是上表，放在 protocol 清單每顆的 `mirrors` 欄，前端不另寫一份。對照雛形第 1 頁標題列。]{.rec}
:::

## 現況盤點：沿用什麼、補什麼 {#inventory nav="現況盤點"}

| 元件 | 現況 | 本案動作 |
|---|---|---|
| 主系統能力點表 `capabilities` | 三段名 `模組.資源.動作`，有 `license_module`、`legacy_name`、`home_route_name` 欄；套件宣告由 `flatten_pkg_migrations.sh` 攤成 `_capabilities.sql` 每次升級重跑 | **沿用**。26 顆由 jedi-remote-agent 的 `CAPABILITIES` 宣告，攤平自動進表；角色授權展開與刪舊顆另寫一支主線 migration |
| 簽票 `RemoteAgentConsoleTicketRoute` | 逐顆 `capability_checker`，持有的寫進 `scope` | **沿用**，清單換成 26 顆 |
| 離線名單 `OfflineOperatorService._scopes_for` | 每次心跳依使用者當下能力點算，整份下發 | **沿用**，對照表換成「清單中離線可下放的」 |
| Agent 驗票 `sync/domain/agent_auth.py` | 不認得的範圍整張拒 | **改**：丟掉並記數（D2） |
| Agent 守門 `console/api/*.py` 約 60 條 `require_session` | 7 個範圍名 | **改名**：一對一換成新顆；`runs_routes` 的來源判斷改歸掃描（D3） |
| Agent `shared/constants.py CONSOLE_SCOPES` | 硬寫 7 個 | **改**：從 `jedi-agent-protocol` import |
| jedi-remote-agent `contract.py` 三張表 | `CAPABILITIES` 11 顆、`CONSOLE_SCOPE_CAPABILITIES`、`OFFLINE_OPERATOR_SCOPE_CAPABILITIES` 硬寫 | **改**：三張表全部從 protocol 清單推導，不再手寫 |
| `jedi-agent-protocol` | 事件碼、錯誤碼、指令、設定、事件、信任錨；**沒有**權限範圍 | **新增** `console_scopes` 模組：資源、動作、顯示名、離線可下放旗標；三邊鏡像測試 |
| 主控台前端 `console/router.js` | 每頁 `scope` 硬寫、`isVisible` 任一命中 | **改名**＋各 view 的 `canDownload`／`canConfigure` 換新顆；`/api/me` 回丟掉的數量 → 橫幅 |
| 主系統 `_ADMIN_CAPABILITIES` | 約 40 個端點守舊 7 顆 | **改**：D7 對照 |
| 角色頁 `PermissionMenuTree` | 選單頁 → 子頁（`tree_page`）→ 能力點三層；動作欄順序 `ACTION_ORDER` 已有 `execute`、`export`，**沒有 `download`** | **補** `download` 進排序；D4 子頁一列 `ui_routes` |
| `gen_permission_matrix.py` 空殼判定 | 掃主系統與 jedi 套件原始碼有沒有人守；**沒掃 Agent repo** | **補**：清單來自 protocol 套件（pip 裝在主系統 venv 裡掃得到），守門在 Agent 要標「Agent 端守門」而非空殼 |
| FE i18n `permission-tree.json`／`remote-agent.json` | 11 顆標籤與說明、5 個 `scope_*` 文案 | **換** 26 顆標籤與說明 |
| 離線操作者對話框 | 唯讀顯示該使用者的範圍 tag | **沿用**，標籤換新 |
| Agent 守衛測試 `test_fr166_guards.py` | ops 路由逐支以單一 scope 打一次對表 | **擴**：對表換 26 顆、涵蓋全部 blueprint |

```{.mermaid cap="圖 2 — 三邊改讀同一份清單；現況三處硬寫是漂移來源"}
%%{init: {'theme':'base','themeVariables':{'primaryColor':'#E2F0F1','primaryTextColor':'#14201F','primaryBorderColor':'#0E7C86','secondaryColor':'#EEF2F3','secondaryTextColor':'#14201F','tertiaryColor':'#FBFCFC','tertiaryTextColor':'#14201F','lineColor':'#4A5A5C','textColor':'#14201F','mainBkg':'#E2F0F1','nodeBorder':'#0E7C86','nodeTextColor':'#14201F','edgeLabelBackground':'#FBFCFC','titleColor':'#14201F','clusterBkg':'#FBFCFC','clusterBorder':'#E4EAEB','actorBkg':'#E2F0F1','actorTextColor':'#14201F','actorBorder':'#0E7C86','actorLineColor':'#C7D1D2','signalColor':'#4A5A5C','signalTextColor':'#14201F','labelBoxBkgColor':'#EEF2F3','labelBoxBorderColor':'#C7D1D2','labelTextColor':'#14201F','loopTextColor':'#14201F','noteBkgColor':'#F6EBD5','noteTextColor':'#14201F','noteBorderColor':'#9C6B12','activationBkgColor':'#EEF2F3','activationBorderColor':'#C7D1D2','sequenceNumberColor':'#FFFFFF'}}}%%
flowchart LR
    P[jedi-agent-protocol<br/>console_scopes：26 顆清單<br/>資源／動作／顯示名／離線可下放]
    P --> R[jedi-remote-agent<br/>CAPABILITIES 宣告<br/>簽票範圍<br/>離線名單範圍]
    P --> A[evidence-agent<br/>CONSOLE_SCOPES<br/>require_session 守門<br/>不認得的丟掉]
    R --> M[主系統 BE<br/>_capabilities.sql 攤平進表<br/>_ADMIN_CAPABILITIES 守門<br/>角色授權展開 migration]
    M --> F[主系統 FE<br/>角色頁 26 顆<br/>離線操作者標籤<br/>capabilities.js 重產]
    A --> C[主控台 FE<br/>router.js 每頁 scope<br/>按鈕看各顆<br/>舊版橫幅]
```

## 資料模型草案 {#data nav="資料模型"}

**不新增任何表。** 變動只有三處：

- `capabilities` 多 26 列、少 7 列（D5）。`module=agent`（新模組，角色樹第一層多一組「Agent」）、`resource_type=files` 等 11 種、`action` 四種、`license_module=remote-agent-manage` 不變、`home_route_name` 指向 D4 的子頁。
- `ui_routes` 多一列：`remote-agent-console`，`is_menu=false`、`tree_page=true`、`pid=remote-agent-manage`（D4 A 案）。
- 票與離線名單的 `scope` 欄值從 7 個短字串換成 `files.download` 形式，欄位型別不變。

命名規則：票上的範圔字串＝能力點名去掉 `agent.` 前綴。Agent 端不需要任何對照表。

**模組為什麼是 `agent` 不是 `detection`（開卡後資安審查補）**：出貨 seed 四個系統角色帶 `detection.*.*`／`detection.*.read` 萬用字元，放 `detection` 底下新裝客戶的稽核主管會自動拿到全部 26 顆、唯讀角色拿到 11 顆檢視。FR-166 的 7 顆已踩在這個洞上，本案一併補掉。

## 排除的方案 {#rejected nav="排除方案"}

| 方案 | 為什麼不 |
|---|---|
| 只拆 `download-files` 成 4 顆，其餘不動 | 「設定」包九頁的問題還在；下次再拆等於再做一次三邊同步 |
| 在 Agent 端自己做角色與權限表 | Agent 單租戶、無使用者表，主系統已是權限真相來源；兩套真相是 FR-048 收斂掉的病 |
| 票上帶位元遮罩縮小體積 | 8 KB 餘裕夠（D8），可讀性除錯時值錢 |
| 舊顆保留標退役 | 第二套真相；矩陣產生器與角色頁都要多一個狀態 |
| 維持「不認得的範圍整張拒收」 | 升級順序硬性 Agent 先；現場漏一台整台登不進；丟掉不會多給權限 |

## 不做什麼 {#out nav="不做什麼"}

- 不做「某一台 Agent 給某人特別權限」——權限綁角色，所有 Agent 一致；離線操作者只決定「能不能離線登入這台」，範圍仍是角色算的。
- 不做 Agent 端自訂角色。
- 不動主系統 Agent 管理頁本身的 4 顆（新增／檢視／修改／刪除 Agent）。
- 不做舊版主系統配新版 Agent 的相容——Agent 收到舊 7 個名字一律不認（丟掉），等於舊主系統發的票進不來；升級順序主系統先。

## 先看哪裡 {#next nav="下一步"}

1. 點雛形 `prototype/index.html`：第 1 頁角色設定頁、第 2 頁稽核員看到的主控台、第 3 頁舊 Agent 橫幅、第 4 頁離線操作者對話框。
2. 裁 D4～D9。
3. 落 design.md 與拆卡表（`handoff/cards.py` 先驗批次再寫），開 Notion 母卡與子卡。批 1 固定是環境卡。
