# FR-173 交接現況（STATE）

> **這份是 living 檔**：每棒就地 Edit，只描述「此刻」。歷史脈絡看同資料夾的 `FR-173-LOG.md`。

| 項目 | 值 |
|------|-----|
| 最後更新 | 2026-11-09 10:20（第 8 棒續：Agent 1.7.4 已發布；早上 201 實測累積 3 個問題待開卡，前門 413 已修 FE repo 未出貨；改善項 7 條仍待開卡） |
| branch | `feature/FR-172`（五個 repo，與 171／172 共用；決策者 2026-11-02 裁） |
| 母案卡 | **CM-3462**；CM-3463～3467 Done、3468 D-1 暫緩；第二輪 CM-3481～3483、第三輪 CM-3485～3492、第四輪 CM-3494／3495 **全部驗收通過待確認**（等決策者 Done）；3484 由 v2.0 取代 Done；url 見 `handoff/notion-cards-*-made.json` |
| 本棒角色 | **發版首腦**（接手者先讀「🔴 此刻：1.30.0／1.7.0 正式發版」整段，再讀 LOG 最後一個 block） |
| 接手前必讀 | 🔴 **`design-v2.0.md`（完整設計，取代 v1.0 `design.md`）**、本檔「設計 v2.0 已定案」段、`vault-status.md`、FR-167 `release-runbook.md` |

## 🧭 原始需求 / WHY

> **這節寫一次，之後各棒不動。**

決策者 2026-11-01：「我看一定要我主本機去簽章，我想把這個 secret 放到 gitlab secret 讓他自己去簽有機會嗎？因為這應該是要自動化的。」「release note 以及最小相容版本應該可以放在 CI 前的欄位。」「主系統／agent 的 CI 要分開；前端也是。」「CI 應該是準備出版的最後一步了。」

目標：BE、Agent、FE 各一支活的 CI；蓋章從 Mac 搬到自架 Vault（鑰匙拿不出來、CI 用 GitLab 短效身分要簽名）；建置期祕密進 Vault。排在 171／172 之後，開發不受影響。

**冷接自檢**（讀完能答再開工）：①蓋章為什麼不放 GitLab 變數、也不用雲端 KMS？②1.29 用 Vault 簽，為什麼機器不能跳過 1.28.0？③6 張卡分 3 批，批 1 兩張開工前決策者要先做哪兩件事？④11-03 新增的 `--internal-test`／`--skip-prod-key-check` 略過 SBOM，跟 CI package 段的關係是什麼？

## 🔴 此刻：主系統 1.30.2、Agent 1.7.4 已發布（1.7.2 撤回）；201 跑 1.7.3、待決策者早上從主控台升 1.7.4（2026-11-09 03:00）

| 產品 | 版本 | 狀態 | 備註 |
|---|---|---|---|
| host | **1.30.2** | published | BE `v1.30.2`＝`6d4930c28`、FE `1e5b15e4`；開包驗全過（權限、更新站網址檔、四種 tpm2） |
| agent | 1.7.0 | published | 目前客戶看到的最新 Agent |
| agent | 1.7.2 | **withdrawn**（00:27） | 正式模式開機即崩（sync/__init__.py 少 import logging），0 下載；以 wrangler d1 執行與後台撤回相同的 UPDATE（後台撤回要 Access 登入，CI token 不准） |
| agent | 1.7.3 | published（01:07，pipeline 3042226434） | `v1.7.3`＝`9159d59`；修 import＋交付 smoke 第 6 項（full 模式首次開機，本輪實跑通過）；min_host 1.30.0 |
| agent | **1.7.4** | **published**（約 02:55，pipeline 3042358611） | `v1.7.4`＝`0d7fe25`（修正 `a17779a`）；FR-185.H-1 CM-3727：心跳失敗短退避、長輪詢恢復叫醒心跳、從沒連上過不判成離線停用；min_host 1.30.0 |

**1.7.4 的由來（11-09 凌晨）**：決策者在 201 裝好 1.7.3 後，Agent 核准後 5 分鐘才顯示在線，期間主控台誤報「離線太久已停用」、掃描反灰。根因：待核准時第一跳 403，心跳睡滿 300 秒；last_ok_at 為空被判成停用。雲端回 403 給待核准是設計不改，修在 Agent。**雲端主系統每 6 小時才向更新站查一次 Agent 新版**（`core/scheduler_update.py` `CHECK_INTERVAL_HOURS=6`），上次 23:26 查到「沒有新版」；下次約 05:26 自動查，之後 201 主控台更新頁才看得到 1.7.4（或決策者在主系統更新中心按檢查）。188 為發版清空間：刪 1.7.2（撤回）、1.6.0、1.5.x 安裝包與映像，23G→44G。

**201 已備妥（01:40）**：`~/agent-1.7.3/guidant-agent-compose-1.7.3/` 已下載、雜湊核過、解開；決策者已 `uninstall` 清掉 1.7.2 半套。第一次 `sudo ./install.sh` 被環境檢查擋：/var/lib/docker 只剩 7.9G（要 12G）——1.7.0／1.7.2／1.7.3 三顆 agent 映像各 8.6G（1.7.3 是首腦多做的 `docker load`）。首腦已刪 1.7.0、1.7.2 映像（無容器使用），剩 24G。**決策者自己重跑安裝**；接手不要代為安裝。

**201**（`jedi@192.168.50.201`，48G 碟；jedi 有 docker 群組、sudo 要密碼；時區 UTC）：手動裝／移除不會清舊 agent 映像（升級流程才只留兩版），一顆 8.6G，連裝兩三版就塞滿。

**同版帶上的修正**（FR-185 全部＋日誌下放＋四種 OS 離線 tpm2＋出貨包更新站網址），詳見 FR-185 R-1 卡 CM-3666（暫緩，已回寫出版結果）。出貨基線已含到 support-route migration（BE `0f1607652`）。

**已發布版本的待補（收尾，等令）**：v1.30.0／1.30.1／1.30.2 release note 的 SBOM 數字；190 Agent 假包升級驗證（runbook 7.5）；1.30.x spec-site 快照；FR-185 母卡與 R-1 等決策者 Done。

**11-09 早上 201 實測累積的問題——已開卡為 FR-188（母卡 CM-3728，15 張子卡 7 批，等工作坊派）**；下列保留查證細節：
0. **問題 4：雲端 jediadmin 新增設備被 RLS 擋（500）**：jediadmin 是「新增租戶」後另以「新增使用者」建的，沒選部門 → `user_org_units` 無資料 → 新增設備時自動帶的 `org_unit_id` 為空 → `devices_insert` 要求部門在允許範圍內，空值必不過。Billows 由首次設定精靈建，管理員有掛部門所以沒事。根因：新增租戶刻意不建管理員（`jedi_iam` `tenant_provisioning_service` 註解明寫）、新增使用者部門選填、被 RLS 擋只顯示 500。決策者要求先講原因、未裁處理方式；雲端資料未改。
1. **Agent 英文模式下檢測工具名稱與表單仍是中文**：主系統 `config.detection_tools` 名稱只有一欄、`config_field_schema`／`credential_group_schema` 的 label／description 只有中文；`core/plugins/_agent_tool_schemas.py` 送 `name_i18n` 時英文直接填中文。主控台 `console/views/Tools.vue` 已會讀 `name_i18n`。建議英文存進工具資料（名稱加英文欄、schema 每欄帶英文），不要在 FE 依工具代號逐欄對照。9 支工具，GCB／InSpec 各 11 欄＋2 組。主系統工具設定頁讀同一份，英文模式應同樣是中文（未實查）。
2. **版本說明只有中文**：Agent `RELEASE_NOTES.md` 與主系統 release note 都單語；出包取前 5 條。建議分中英兩組存、出包產兩份（舊欄位放中文，新增英文欄，舊版不認得會略過），畫面依語系顯示、缺英文退回中文；不建議中英並列（只取 5 條會少一半內容）。說明會進簽章清單，從下一版開始，1.7.4 不補。
3. **第三方元件掃描結果沒回到主系統、沒有 PDF**（PDF 本來就由主系統收到結果後產）：
   - ① Agent 待回傳佇列只在心跳成功後送：09:57:54 掃完，晚上一跳 2 秒，等到 10:02:57 才送。建議掃描完成就叫醒佇列（`outbox.request_drain()` 既有）。
   - ② **已修 repo（FE `908a78be`，未出貨）**：主系統向 Agent 要檔（send_file），Agent 回 `POST /api/1.0/agents/replies/<id>` 被前門 nginx 413（全站 1m，該路徑不在 110m 清單）；主系統 30 秒等不到 → `FILE_AGENT_500001`「檔案 agent 無法連線」→ `compliance.source_scans` 該筆 failed。修法：`nginx.onprem.conf` 110m 清單補 `agents/replies/[^/]+`；docker 實測 5MB 舊 413、新 200，其他路徑仍 1m。**跟下一版主系統出貨**。🔴 **雲端已臨時套用（決策者 11-09 10:51 放行，為了先測功能）**：`guidant-fe` 容器內 `/etc/nginx/conf.d/default.conf` 改同一行並 reload，備份 `default.conf.bak-20261109-105116`（同目錄）；實測 3MB POST replies 由 413 變 401（到後端）。**重建或升級 guidant-fe 會還原**，下一版主系統出貨後要確認新映像本身帶修正（`docker exec guidant-fe grep -c agents/replies /etc/nginx/conf.d/default.conf` 為 1），再刪備份檔。容器 cap_drop ALL、uid 101：寫檔要 `docker exec -u 0`，暫存檔放 conf.d（/tmp 歸 nginx，root 也寫不進）。
   - ③ 取檔失敗的錯誤訊息應區分「被前門擋（413）」與「Agent 連不上」，不該一律寫無法連線。
   - 雲端那筆掃描已記 failed 不會自己恢復；前門修好後要在 Agent 按「重新執行」。
   - ④ 兩邊狀態矛盾：Agent 只看「紀錄送到」就標「已回傳」，主系統要「取到檔並處理完」才算成功（決策者：Agent 看到成功不對）。建議 Agent「回傳主系統」分三態：已送出（主系統處理中）／已回傳（主系統取檔處理完成）／主系統處理失敗（附原因），最終狀態由主系統處理完回報 Agent。失敗原因畫面寫 InternalServerError，要寫實際原因。
   - ⑤ **重傳報告（不是重新執行）兩邊都要能按**（決策者 11-09 裁）：報告檔還在 Agent 的 SeaweedFS，失敗的只是取檔那步。Agent 端狀態為「主系統處理失敗」時給「重傳報告」；主系統「Agent 掃描執行紀錄」失敗列給「重新取檔」；主系統對同一 `(agent_uid, agent_local_uid)` 且目前失敗的重送要重新取檔處理，不能當重複忽略。實例：10:48 那筆的報告在前門修好後 10:53:19 已自動重送成功，但主系統請求早已逾時結案，檔案沒被接回處理。「重新執行」是重掃（重上傳、重跑 Syft 與三套比對、多一筆紀錄），不能拿來當重傳。三個 repo：主系統（先）、Agent、FE 各一張。
   - ⑥ 主系統取檔請求 30 秒逾時後就結案，Agent 佇列裡被擋的回覆仍以 1/2/4/8 分至 1 小時重試，主系統不再收；應回「請求已結束」讓 Agent 停止重試。
6. **問題 6：主系統產出的 PDF 沒送回 Agent**，現場在 Agent 上只看得到原始 JSON。建議主系統處理完把 PDF 回送 Agent、併進該筆執行紀錄，與問題 3 ④ 一起做。
7. **問題 7：Agent 手動第三方元件掃描在所有安裝版都失敗——已修 repo＋雲端**。API 收 Agent 回傳檔寫進 spool（預設 `/tmp/agent-outbound`），讀檔的是 worker；兩容器 `/tmp` 各自 tmpfs，worker 讀不到 → `FILE_AGENT_500002`「Agent 回 done 但沒帶檔」。修法：production compose 共用環境段加 `AGENT_SPOOL_DIR=/home/guidant/.agent-spool`（`/home/guidant` 已是三服務共用的主機資料夾）。BE `4f09e9033`，跟下一版主系統出貨。**雲端已套用（11-09 11:44，決策者放行）**：compose 備份 `/srv/guidant-ai/docker-compose.yml.bak-20261109-114116`，`guidantai start` 只 recreate api／socketio／worker，九服務 healthy，探針驗證共用。下一版升級會換新 compose（已含此行），屆時刪備份。本機 DEV 測不出來（api 與 worker 同一台 Mac 共用 /tmp）；CINC Auditor 等 local-runs 不受影響（報告只存參照、由 API 當場取）。
5. **刪除執行紀錄：決策者 11-09 裁「先不要做，太麻煩」，不開卡、不再提**。現況：Agent「執行紀錄」與主系統「Agent 掃描執行紀錄」都不能刪；主系統第三方元件風險頁已有刪除但只准刪失敗的（成功的是比較基準），刪除寫稽核事件。
4. **（回答，非問題）Agent 映像內建的掃描工具**：CINC Auditor 7.2.1、Syft 1.55.0、Trivy 0.76.1、Grype 0.121.0、OSV-Scanner 2.7.0、sonar-scanner 8.1.0、LibreOffice 25.8.7＋思源黑體（清單在 Agent `scripts/build/tools-manifest.txt`）。OpenSCAP／Nmap（SSH 到目標或跳板機；Nmap 授權不能包）、OpenVAS（客戶 GVM）、ZAP（客戶 ZAP）、SonarQube 伺服器由客戶提供。

**決策者 11-09 同意方向、尚未開卡的改善**（每次發版都要修幾輪的根因：某些檢查只在正式發版才跑）：
1. 測試版發布補跑全量測試（BE 守衛＋FE vitest＋Agent pytest），批次合回後、包版前先跑一次測試版發布。
2. 映像弱掃前移：Agent tools-manifest（約 60 項）與固定 digest 基底映像在 verify 就掃；OS 套件只能預掃；建完映像那次保留。
3. 交付 smoke 能用原始碼跑的（第 5 項註冊鏈路、第 6 項首次開機）做成一般測試進全量。
4. Agent CI 加 pyflakes undefined-name（這次的 bug 幾秒就抓得到；要加 dev 相依，改 poetry.lock）。
5. Agent 安裝中途失敗時，提示改用安裝包 `install.sh uninstall`，或把裝維運指令提前（201 實踩：失敗後移除指令不存在）。
6. Agent 安裝／移除後清舊映像：uninstall 與全新安裝不清同 repository 舊 tag，連裝幾版就塞滿 48G 碟（201 實踩）。
7. Agent 映像 8.6G 偏大（LibreOffice、cinc-auditor、掃描工具），評估瘦身或拆分。
- version-bump Step 0.5（打 tag 前本機跑三 repo 全量）已加：`4a1bce951`。

**本機守衛落差（CI skip，未處理）**：test_permission_matrix_three_way 三條、test_security_shape_ai_socket_agent 兩條、test_jedi_rule_bodies_mirror_be。

**188**：硬碟約 45G；BE 工作樹 `6d4930c28`。

## §1 當前狀態

| 項目 | 狀態 |
|---|---|
| design.md | 11-03 修訂定案（D10～D13、時序圖 §2、決策者功課 §5、時程 §7 約 2 工作天），6 張卡 3 批 |
| Notion | 已開卡未派（`handoff/gen_notion_cards.py` 產；批 1 V-1、C-3／批 2 C-2、C-1／批 3 C-4、D-1），**未建工作坊** |
| 前置案 | FR-171、172（含 172.1）、174 皆結案 Done；五個 repo 都在 `feature/FR-172`。190：主系統 1.28.3、Agent 1.5.5（測試章簽、已上站）；189 POC 仍 1.27.x |
| **Vault（192.168.50.172）** | **已架**：2.2.1、5 取 3、swap 關、稽核開、Transit ed25519 鑰 `guidant-release`（kid `05086455d42ca0d6`，三個 false）、jedi 管理者帳號、root 已撤。全部細節見 `vault-status.md` |
| Vault 待補（決策者自己做） | 每日快照＋異地備份、防火牆——決策者裁先開發，**正式出版前一定要補** |
| Vault 公鑰 | 已隨 1.28.0 進 BE `scripts/installer/release-keys/` 與 `PROD_KIDS`（FR-172 S-4）；1.29 改用 Vault 簽時機器不能跳過 1.28.0 |
| Vault 待補（決策者做，卡開工前） | 只能簽章的開發帳號（V-1 前）；GitLab OIDC 角色、建置期祕密進 KV、188 信任 CA（C-1／C-2 前）；確認 docker runner（C-3 前） |

## §2 已定裁示（不要重新討論）

| 裁示 | 何時 | 誰 |
|---|---|---|
| 自架 **HashiCorp Vault Community**（不選 OpenBao：功能同、文件少；內部出版用 BSL 不受限；日後要換指令與 API 相同） | 2026-11-01 | 決策者 |
| 不選 GitLab Secrets Manager：公司是 GitLab 免費版，它要 Premium，且只存祕密不開放簽章 | 2026-11-01 | 決策者 |
| 不選雲端 KMS（不支援 Ed25519，要換演算法改三處驗章）、不把私鑰貼 GitLab 變數（反模式）、Cloudflare 無 KMS | 2026-11-01 | 決策者 |
| 專用 VM 192.168.50.172，apt 裝 systemd 服務，不用 docker；單節點 | 2026-11-01 | 決策者 |
| 管理者帳號名 `jedi`；只有決策者一人管；解封鑰匙 Apple「密碼」3 把＋離線紙本 2 把 | 2026-11-01 | 決策者 |
| 快照、防火牆先不做，先開發 | 2026-11-01 | 決策者 |
| 本案排在 171／172 之後；**1.28.0 不等本案、Mac 手簽先出，本案跟 1.29**（2026-11-02 改裁）；1.28.0 包內先附 Vault 公鑰（FR-172 S-4 做），1.29 才能換章 | 2026-11-01、11-02 | 決策者 |
| update-center、License Center 不進出版管線 | 2026-11-01 | 決策者 |

## §3 下一步

1. ✅ V-1（CM-3463）驗收通過，update-center 已合回 `feature/FR-172`（`9c363ab`）。部署 Worker 時決策者要：後台「印章」登記 `05086455d42ca0d6` 為 primary；Cloudflare Access 放行 GitLab 打 `/admin/releases/*/publish`。
2. ✅ Vault：14.1 測試章、14.2 `release-dev`（只能簽測試章）、14.3 測試章公鑰只在 190、14.4 JWT、14.5 五筆 KV（逐欄與 188 比對一致）、`ci-fe`＋`fe-ci`。
3. ✅ C-3（CM-3464）合回 FE `feature/FR-172`（`eb63f95c`）、已推；GitLab 實跑 pipeline 3022544900 通過：`test` 綠（78 檔 584 條）、`vuln-scan` 綠（Critical 0）、`lint` 黃（397 條既有錯誤，allow_failure）。實跑前補了兩處設定：FE 專案「CI/CD configuration file」原指 `.gitlab-ci-terraform.yml`（C-3 刪掉的舊檔）→ 決策者清空；188 未信任 Vault CA（runbook 第 11 段從沒做過）→ 決策者裝上。
4. ✅ 第二批準備就緒：Vault `ci-release`／`ci-test` 政策、`release-ci`／`test-ci` 角色（都綁 `user_id`＝21126655）；GitLab BE、Agent `v*` 受保護 tag（Maintainers）、FE job token 允許清單已含 Agent。C-3 驗完、V-1 改 Done 後工作坊派第二批。
4c. ✅ 188 上 BE、FE、Agent、jedi-python-package、update-center 五個 repo 都在 `feature/FR-172`（決策者要求，jedi 原在 feature/FR-139 快轉 40 個 commit）；update-center 推上 GitLab 並 clone 到 `/opt/update-center`；FE C-3b 推上。C-1／C-2 共用 188 主機鎖 `/home/jedi/.guidant-build.lock`（resource_group 不跨專案）、蓋章工具在 188 用 node 容器跑 `/opt/update-center` 的 CLI。
4b. ✅ jedi 群組 runner：決策者在 `commonservice3` 註冊 `188-guidantai-build-jedi`（id 58355505，188 shell、tag `guidantai-build`）。首腦讀 `gitlab-runner list` 時遮罩失效，188 兩個 runner 的認證 token 印進對話紀錄 → 決策者 2026-11-03 14:47 UTC 在 188 跑 `gitlab-runner reset-token --all-runners` 重設，兩個 runner 讀回仍在線、`token_obtained_at` 已更新。
5. 第二批 CI 驗完後立刻：刪 188 上 `/opt/guidant-ai-*/.env` 的 License Center token、`~/.fr167-r2.env`、`~/.npmrc`、BE 專案 GitLab 變數裡的 R2 與 Bugsink；到 License Center 換新 token 放進 Vault（188 runner 以 jedi 跑，任何 job 都讀得到那些明文，含 FE 每次 push 的檢查）。
6. 正式出 1.29 前：Vault 快照＋異地備份、防火牆；189 POC 先升到 1.28.x；License Center 送簽走 http（內網明文 token），另案評估改 https。

> ⚠️ 這節是建議清單，不是執行授權。接手方讀完盤點完即停，等決策者發令。

**🔴🔴 設計 v2.0 已定案（2026-11-04 下午，決策者裁；CI 首腦從這段開始讀）**

決策者審系統說明時判定 v1.0 流程把「發給測試機」與「正式發給客戶」混在一起、正式發版要人介入五次，違背本案「自動化」目的。重新定案，完整設計在 **`design-v2.0.md`**（完整文件，不必對照 v1.0）。三條路，各一個入口、各自參數：

| 路 | 觸發 | 檢查 | 終點 |
|---|---|---|---|
| ① 正式發版 | 推受保護 `v*` tag | 測試＋弱掃全跑；`rehearse` 勾才演練（主系統、Agent 都可選） | **自動發布**給客戶，沒有手動 publish job |
| ② 直接部署 | 任一 branch，`target` 可複選 190／STG／POC | 不跑測試與弱掃、不簽出版章 | `install.sh --upgrade`（Agent：`guidant-agent-compose upgrade`）直接裝 |
| ③ 測試版發布 | 任一 branch | 不跑測試與弱掃；測試金鑰簽 | 登記成只有內部三台看得到的草稿，到該台更新中心按更新（取代決策者 Mac 的 `publish2.sh`） |

**與下方舊段落衝突時以本段為準**：
- 更新站「發布前內部先裝清單不能空、每台須成功」**移除**（下方「發版原則」段寫的「內部先裝全部成功才准發布」作廢）。
- 內部三台（190／STG／POC）**都可直接部署、都裝測試金鑰公鑰**；`deploy_e2e.sh` 與 `deploy_agent_e2e.sh` 解除只准 190。v1.0「測試金鑰只放 190」的前提不是決策者裁的，作廢。
- `deploy-stg`／`deploy-poc`（正式包尾端自動部署）與 `environment` 參數刪除；直接部署改走 ②。`deploy_only` 併入 ②（`reuse_bundle`）。
- 版本說明由 CI 隨版本送更新站（v1.0 C-1 漏做）。FE 映像同一台 188 本機優先、Harbor 備查（D11）。Agent 離線檔一併上 R2。
- CI 設定檔拆成分流主檔＋三支子設定檔（`release.yml`／`deploy.yml`／`test-release.yml`）。

**卡片影響**：批 4（CM-3481、3482、3483）不受影響，照常。**CM-3484 由 v2.0 的 CI 改寫取代**，決策者會在狀態頁按「這張不用做」。

**✅ CI 首腦已拆卡（2026-11-04 下午）**：第三輪 8 張卡 CM-3485～3492、2 批（底表 `handoff/cards_r3.py`，產卡 `gen_notion_cards_r3.py`）。批 4 與 CM-3481／3482／3483 同批（共 8 張，全部不同檔）：U-1 更新站規則／B-2 BE 腳本／A-2 Agent 部署腳本／A-3 Agent 登記腳本／F-1 FE 不刪映像；批 5：B-1 BE CI 三條路／A-1 Agent CI 三條路／U-2 後台離線檔連結。決策者拆卡前裁三件（寫在 cards_r3.py 檔頭）：①正式發版一個動作＝Run pipeline 選受保護 tag（不是推 tag 觸發）；②Agent 演練樣本 db 放 188 `.build/rehearse/agent-<舊版>.db`，第一份決策者從 190 匯出；③離線檔連結沿用 `presignDownload`。§7.3 前置已寫進 U-1／B-1／A-1 卡。**批 4 八張 2026-11-04 下午全部驗收通過（update-center 173＋99 測試本機重跑綠；Agent 合回時 README 工具表撞檔，首腦兩邊保留解掉）。批 5 分流寫法定案 include 層＋inputs 下拉（已 append CM-3490／3491），等決策者放行批 5。**

**文件**：`writing-technical-docs` skill 已完成（`.claude/skills/writing-technical-docs/`）；系統說明 `出版管線總覽.md` 尚未照 v2.0 重寫（文件首腦負責，等 CI 改完實跑後一起改）。

- B-1（CM-3490）已合回待驗：總覽要照 v2.0 重寫；直接部署目標定為三個勾選框 `deploy_e2e`／`deploy_stg`／`deploy_poc`（不用逗號字串），job 清單見 FR-167 `release-runbook.md` 步驟 2～4。

**📨 CI 首腦 → 文件首腦（2026-11-04 下午）：拆卡時與 v2.0 文字有出入、或文件還沒寫到的事，更新 `design-v2.0.md`／`出版管線總覽.md` 時請一併對齊**

1. **正式發版的觸發方式改了**（決策者 11-04 裁）：v2.0 §1 表、R1、圖 3 第 1 步、圖 6 第 1 步都寫「推受保護 `v*` tag」。實際做法是 **在 GitLab Run pipeline 選那個受保護 tag**（可填 `rehearse`／`rehearse_base`／`fe_ref`）。原因：推 tag 觸發的 pipeline 沒有參數畫面，三個參數只能用預設；且 FE 沒有同名 tag，`fe_ref` 預設「同名」會找不到。打 tag 本身交給 `version-bump` 流程。「人工只有一步」不變，只是那一步是 Run pipeline 選 tag。BE／Agent 的 `workflow:rules` 維持只收 web／api 觸發。
2. **Agent 演練的樣本資料來源**（v2.0 §6.5 只寫「放入帶資料的 agent.db」）：決策者裁 188 固定放 `.build/rehearse/agent-<舊版號>.db`，第一份由決策者從 190 現行版匯出，之後每次 Agent 進版順手留一份。主系統演練吃的是 STG 唯讀 dump，Agent 沒有對應來源，這是補的規則。
3. **離線檔下載連結**（v2.0 §6.5 表「R2 短效網址」、§7.2 最後一列）：沿用更新站既有 `presignDownload`（`src/releases.ts:195`，R2 預簽 15 分鐘網址，客戶主機下載安裝包就是走它），後台版本詳情多回一個 `offline_download_url`。不新增金鑰、不新增機制。文字可寫準成「後台取得 15 分鐘有效的預簽下載網址」。
4. **直接部署的 `target` 多選**（v2.0 §4.9 表「可複選」）：GitLab `spec.inputs` 沒有多選型別。B-1 卡讓小弟在「`options` 單選＋逗號分隔字串」或「三個 boolean」擇一並回寫理由；文件寫 pipeline 參數表時等 B-1 合回看定案再寫。
5. **CI 檔案佈局（決策者 11-04 傍晚定案）**：主檔 `spec.inputs.pipeline` 下拉（`release`／`deploy`／`test-release`，預設 `deploy`），**`include:` 用 `rules:` 在主檔分流、一次只載一支路的子檔**（`common.yml` 無條件；三支路各認自己的值且排程不載；`vulndb.yml` 只在排程）；子檔內的 job **不寫**「我是哪條路」的規則。受保護 tag 檢查留在 `release.yml` verify＋Vault 角色。子檔放 `.gitlab/ci/`：`common.yml`（既有 `.vault`／`.sync_repo`／`.in_repo`／`.collect`）、`release.yml`、`deploy.yml`、`test-release.yml`、`vulndb.yml`。v2.0 §4.9 寫「依觸發方式與一個 `PIPELINE` 變數分流」——實作是 inputs 下拉不是手打變數；只提三支子檔，實際五支。
6. **已查明、文件可能要記的現況**：BE 測試包 3025154404 的 `build-be` 第一次在 GitLab 上就通（Vault `test-ci` 登入、188 編譯鎖、Nuitka 813 秒、smoke 自動改走臨時庫、出映像）——總覽 §8「待實跑」那幾列可以更新成已驗；`fe-pipeline` 失敗真因是 `trigger:branch` 不吃 job `rules:variables` 設的變數（與 `inherit.variables` 無關），總覽 §排錯那列的「原因」要改。
7. **三台 `guidant-seaweedfs` unhealthy 的根因**（如果總覽有「出事怎麼辦」段要收）：healthcheck 的 busybox `wget` 走 https 每 5 秒 fork 一個 `ssl_client`，PID 1 是 `weed` 不收屍，約 3 天撞滿容器 pids 上限後 `docker exec` 開不了行程、永遠 unhealthy，服務本身活著。修法 CM-3483 在主系統 compose 加 `init: true`＋`pids_limit`（Agent compose 早有）。症狀判準：`docker exec` 回 `procReady not received`＋dmesg `fork rejected by pids controller`。暫時清法 `guidantai restart guidant-seaweedfs --force`（不 `--force` 會被「設定比容器新」守門擋）。
8. **卡片對照**：第三輪 8 張 CM-3485～3492 與每張對應的 v2.0 決策編號在 `handoff/cards_r3.py`（`ren`／`why`／`accept` 三欄）；CM-3484 已由本輪取代。

**📨 第二批（2026-11-04 傍晚，批 5 合回＋實跑後）**

9. **直接部署實跑成功**（pipeline 3025779481）：190 升到 1.28.3，約 30 分。GitLab 畫面標 failed 是 FE 下游 `lint`（allow_failure）被 `strategy: mirror` 鏡射上來，九個 job 全綠——排錯表可記一列「直接部署顯示 failed 但 job 全綠」。FE 映像實測「取本機」（D11 生效）。
10. **測試版發布的版本說明改為選填**（決策者裁，`e963812e6`）：Run pipeline 多一個 input `note`（只對測試版發布有效，500 字內）。有填→當唯一一條版本說明；沒填→讀 release note 檔尾；都沒有→送空並警告，照常登記。**正式發版不變**（缺說明就擋）。v2.0 §4.9 參數表、圖 5 第「登記版本」步要補；R2 寫的是正式發版，不受影響。
11. **同一份程式不重編 BE**（`0b394862c`）：直接部署、測試版發布時，BE 映像多標 `src-<最後改到程式的 commit>`（排除 docs／.gitlab／.gitlab-ci.yml／test），188 本機有就跳過 Nuitka（省約 17 分）。正式發版不吃這個判斷、永遠重編。`skip_be` 仍保留、優先。§6.3／6.4 的時間估計可補一句。
12. **CI 打更新站 `/admin/*` 要過 Cloudflare Access**（`80163cb56`／Agent `be85eb5`）：決策者裁用 **Service Token**（不用 Bypass）。CI 請求多帶 `CF-Access-Client-Id`／`Secret`，存 Vault `kv/ci/update-site` 的 `cf_access_client_id`／`cf_access_client_secret`；Access 應用程式加一條「服務驗證」原則選 token `guidant-ci`。更新站程式收到 `Authorization` 時只認那個憑證、不看 Access 給的身分，所以程式不用改。v2.0 §6.6 角色表的 `kv/ci/update-site` 欄、§6.1 架構圖「登記版本、發布」那條線、§7.3 前置作業都要補這件；系統說明的機敏資訊表多一項（Service Token，有到期日要換）。
13. **測試版發布實測到 v2.0 D8 生效**：用 1.28.3 登記被更新站回 409 `version_already_published`（1.28.3 是 11-03 Mac 測試章發布過的）。今天改用 1.28.4 跑通（BE `f7fbfe495`、FE `60a8a8cc`）。
14. **測試版改用預發版號**（決策者裁，開卡 CM-3494 BE／CM-3495 Agent，批 6，未做）：測試版用 `X.Y.Z-beta.N`（semver 寫法，不用 PEP 440 的 `b1`——更新站只認 semver），正式版就是 `X.Y.Z`，兩者永遠不撞。v2.0 §4.8「測試版發布只能用尚未正式發布的版號」要改寫成這個規則；卡合回前先別改文件，記一筆待改即可。
15. **內部三台 `/etc/machine-id` 相同**：190／188／189 主機指紋同一個 `ff793254…a080`，更新站內部主機清單登一筆即三台都認；但升級回報會互蓋。1.29 前要重生（見 §4）。系統說明「內部主機清單」那段要寫明現況與限制。
16. **更新站印章表是空的**：正式章 `05086455d42ca0d6` 尚未登記，正式發版自動發布會被 `kid_not_registered` 擋。屬 §7.3「正式出 1.29.0 前」既有項，系統說明前置清單確認有列。

**📨 第三批（2026-11-04 晚，批 6 合回＋直接部署改一次一台）**

17. **直接部署改一次一台**（決策者裁，BE `f3454d5e4`／Agent `79090be`）：三個勾選框 `deploy_e2e／stg／poc` 換成單選 **`target`**（`e2e`／`stg`／`poc`，預設 e2e）。理由：一條 pipeline 動三台不好追蹤、紅了要猜是哪台。換下一台勾 `reuse_bundle` 不重建。v2.0 §1 表「190／STG／POC（可複選）」、§4.9 參數表、§8 驗收 #6、#16b 都要改成一次一台；runbook 已改。
18. **POC 部署要按 ▶**：`target=poc` 時部署 job 是 manual，pipeline 跑到那步停下等人按 ▶ 才升級。說明文字已改白話。
19. **測試版版號一律 `X.Y.Z-beta.N`**（CM-3494／3495 已合回）：主系統與 Agent 測試版發布的第一步就擋不帶 `-beta.N` 的版號；正式發版帶 `-beta` 會擋。寫法只收 semver（`1.29.0-beta.1`），PEP 440 `1.29.0b1` 當格式錯。排序 `beta.1 < beta.2 < … < 正式版`，`beta.10 > beta.9` 數字比；主系統升級（`upgrade_common.sh`）、Agent 升級（`upgrade_order.sh`）、主系統判 Agent 包新舊（`package_verifier.py`，既有）、更新站（`versions.ts`）四處一致。v2.0 §4.8 改寫成這個規則（第 14 點的「待改」現在可以改了）。
20. **Agent 測試版發布的版本說明也改選填＋`note` 欄位**（CM-3495），與主系統一致。
21. **Agent CI 實跑抓到兩個建置 bug**（Agent `b72f2b8`、`bec2019`）：① `build_console_dist.sh` 內 FE 弱掃摘要印在 stdout，污染了 `FE_CONSOLE_DIST` 路徑；② `docker build --output type=local` 把 `dist-console` 建成 700，包進映像後 uid 1000 讀不到，啟動防竄改檢查拒啟。1.5.5 以前主控台在 Mac 打包所以沒遇過。系統說明排錯表可收這兩條。
22. **FE lint 清到 0 錯 0 警告**（FR-176，CM-3496／3497，另一個 session 做）：BE pipeline 不會再因 FE 下游 lint 鏡射成 failed。系統說明排錯表「直接部署顯示 failed 但 job 全綠」那列可標已解。

**📨 第四批（2026-11-04 夜，Agent 測試版發布跑通＋主控台重套 bug）**

23. **Agent 測試版發布跑通**（Agent pipeline 3026549240 success，1.5.6-beta.1）：建置、Vault 測試章、登記草稿、上傳 R2 `agent/v1/1.5.6-beta.1/` 全過，更新站 D1 已核。系統說明「三條路驗到哪」更新：主系統 ②③ 已驗、Agent ③ 已驗（發布端），① 正式發版兩邊都還沒跑。
24. **Agent CI 第一次在 188 跑，共修五個建置問題**（第 21 點只列了前兩個，補後三個）：③ Agent 映像沒設 UTF-8 locale，中文 log 與啟動防竄改的「完整性驗證通過」印成 `????`，建置斷言判失敗——`deploy/Dockerfile.runtime` 加 `LANG=C.UTF-8`、`PYTHONIOENCODING=utf-8`（Agent `502b6a2`；客戶 docker 主機也可能沒 locale，所以修在映像）；④ 蓋章 CLI 對 Agent 一律要求 `--bundle` 產離線檔，測試章也不例外——改成**測試章不產、帶了就擋，正式章才要求**（update-center `56aa2bf`）；⑤ Agent 上傳 R2 用 aws cli，188 只有 rclone——改同主系統用 rclone（Agent `b1ebe7e`）。系統說明排錯表可收這三條；②（dist-console 權限 700）與③ 的共通原因是「主控台前端改由 188 docker 打包、CI runner 沒有登入 shell 的環境」，可寫成一段。
25. **主系統 bug：測試機上 Agent 主控台按「更新到新版」只會重裝現行版**（BE `1f8878e86`）：`core/plugins/_agent_console_update.py request_update` 判同版重套時沒看更新站有沒有新版。主系統手上包＝Agent 現行版、且同版重套開關開著（內部三台都開）時，一律走 reapply，「下載新版再推」那條永遠走不到。190 實踩兩次（audit `action=reapply target_version=1.5.5`）。修法：reapply 多加「更新站沒有相容又更新的版」。正式機開關關著不受影響。系統說明排錯表要收：**症狀**＝主控台顯示「更新到 X」，按下去進度視窗標題卻是現行版號；**判準**＝主系統 `app.log` 的 `AGENT_UPDATE_ROLLOUT_CHANGED action=reapply`。主系統更新中心 Agent 區的推送走另一條路（`agent_rollout_service`），沒有這個問題。
26. **測試版版號實例**：主系統 1.28.4 是正式格式（交棒前用來跑通的過渡號），之後測試版一律 `-beta.N`；Agent 已是 `1.5.6-beta.1`。RELEASE_NOTES.md 段落標題要與版號完全相同（`## 1.5.6-beta.1`），否則讀不到該段（測試版說明選填所以不會擋，但畫面會沒說明）。
27. **系統說明 `出版管線總覽.md` 可以開始照 v2.0 重寫**：主系統 ② 直接部署、③ 測試版發布與 Agent ③ 都已實跑，這三節可用實際紀錄寫作業程序與排錯；① 正式發版那節留空待實跑（要先進版 1.29.0、更新站印章表登記正式章——目前是空的）。

**📨 第五批（2026-11-05，第一次正式發版：主系統 1.29.0、Agent 1.6.0 都已發布）——文件首腦照這批改系統說明**

28. **正式發版兩邊都跑通**：主系統 1.29.0（BE pipeline 3027235959，tag `v1.29.0`＝`8c3d1d930`）、Agent 1.6.0（Agent pipeline 3029934137，tag `v1.6.0`＝`2d936a2`）；更新站兩筆都 `published`、kid `05086455d42ca0d6`（Vault 正式章）。Agent 離線檔第一次產生，與安裝包一起在 R2 `agent/v1/1.6.0/`。系統說明檔頭狀態、§2.3「待實際執行驗證」、§8.1「印章表目前是空的」都過期，要改。§8.1 標題「正式出 1.29.0 前必須完成」改成「正式出下一版前」，還沒做的幾項留著（Vault 快照與防火牆、三台 machine-id、189 POC 升 1.28.x 以上、STG／POC 測試公鑰與同版重套、188 明文憑證）。
29. **客戶機端已實測（正式章驗章升級）**：190 主系統 1.28.4 → 1.29.0 從更新中心升級，八步全 ok（升級單 `20261105-0254-efae`），容器全 healthy、前門與 API 200。這是第一次用 Vault 正式章簽的包在客戶機驗章。
30. **正式發版第一次實跑撞到的坑（排錯表 §9 要收）**——每一條都已修，附 commit：
    | 症狀 | 原因 | 處理 |
    |---|---|---|
    | BE verify `[audit] ❌ 找不到 pip-audit` | `poetry sync --without dev` 把 dev 群組（含 pip-audit、pip）刪了 | 拿掉 `--without dev`（BE `517b19ea2`） |
    | FE 下游 test 584 條全過卻判紅，`insertBefore` of null | `UpdateCenter.spec` 沒 unmount，遺留的 3 秒輪詢在 188 忙時觸發；整檔跑超過 3 秒才會紅 | 測試清畫面前先 unmount（FE `8f9b55ff`） |
    | package `[vuln-gate] ❌ Critical … ruby 3.4.10` | CINC 自帶 Ruby，弱點資料 11-02 才收錄；測試版發布不掃映像，所以到正式版才看到；CINC 最新 7.3.4 仍帶 3.4.11 | 白名單（BE `8c3d1d930` be 列、`2a23805cf` agent 列；image 欄只收單一值，be／agent 各一列；Agent 的關卡讀 188 `/opt/guidant-ai-be` 的白名單，Agent 發版前 188 BE 工作樹要含那一列） |
    | package 掃描段無訊息退出、`be-image.cdx.json` 0 byte | 188 硬碟滿（剩 3.7G）；syft 解映像沒空間 | 清 188 舊安裝包到 44G，只 retry package（不重編） |
    | register-publish 停在 `git fetch -q --tags origin` | 188 本機留著移動前的同名 tag（would clobber；另有 v1.16.0／v1.23.0／v1.24.1 三個舊 tag） | 188 `fetch --tags --force` 後 retry；CI 加 `--force`（BE `58feaeb19`、Agent `efc9409`） |
    | Agent verify 守衛 5 條紅 | ① `zap.py` 模組層鎖（真違規，11-02 加的）② FR-166 守衛掃到 188 `.build/bundle/stage/`（8.1G 解開的舊包）③ `config/version_bake.py` 是產生檔 | 鎖收進 `services()`；守衛排除 `.build` 與產生檔（Agent `efc9409`） |
    | Agent verify pip-audit 擋 37 條 | Agent 第三方套件落後主系統一大截（cryptography 45、PyJWT 2.13、flask-cors 5…）；測試版發布不跑 verify，所以從沒在 CI 跑過 | 升到主系統已用的版本（Agent `199ab1c`） |
    | Agent verify 用舊套件跑 pytest（會假綠） | 188 的 `.venv` 共用，verify 前沒人同步 | verify 先 `poetry sync --with dev`、宣告 pytest 為 dev 群組、verify 加 Vault 登入（Agent `8392172`） |
31. **CI 行為改了**（系統說明 §3.2、§3.3 要改）：
    - **FE CI 只在被 BE 觸發時跑**；push、打 tag、MR、網頁手按都不建 pipeline。測試、弱掃、lint 只在 BE 正式發版觸發時跑（BE 帶 `FE_VERIFY=1`）；直接部署、測試版發布的 FE 下游只建映像（BE `58feaeb19`、FE `5e2c736c`；決策者 11-04 裁，理由：push 頻率太高）。打 FE tag 因此不會再跟 BE 下游撞。
    - **Agent 正式發版打包主控台前跑 FE vitest（紅就停）與 lint（不擋）**（Agent `2d936a2`；原本只跑 FE 套件弱掃）。
    - Agent 正式發版 verify 先同步 `.venv`（第 30 點最後一列）。
32. **紅了怎麼辦（新段落）**：環境類（Vault、Harbor、R2、更新站暫時錯誤、188 空間、188 舊 tag、FE 偶發）→ 修環境後 retry 那個 job，前面綠的不重跑；前提是 retry 前 188 沒跑過別條 BE pipeline。程式碼或 CI 設定（含白名單）→ 修正 commit、移 tag、整條重跑。受保護 tag 刪除要用 `glab api -X DELETE projects/<專案>/repository/tags/<tag>`（`git push --delete` 被 GitLab 擋）；**刪除 API 可能回 400「Failed to remove tag」但實際已刪**，先 `git ls-remote --tags` 查遠端再重打。只在更新站上還沒有這一版時才移 tag。
33. **188 空間（新段落）**：正式發版前確認 188 根目錄剩 30G 以上。11-04 清了 BE 安裝包 1.27.8／1.27.9／1.28.1～1.28.4、Agent compose／原生包 1.4.7、1.4.8、1.5.1～1.5.4、1.5.6-beta.1；保留 BE 1.27.10、1.28.0，Agent 1.5.0、1.5.5。docker 建置快取（約 40G 可回收）與舊映像標籤**未清**，等決策者。Agent 正式版 1.6.0 的包與離線檔另備份在 188 `/opt/guidant-ai-agent/.build/release-archive/1.6.0/`（直接部署會在 `.build/compose/` 產同名測試包蓋掉正式版）。
34. **正式發版時間**（§6 可記）：主系統約 45 分（verify 1、BE 編譯 17、映像掃描 6、打包 5、推 Harbor／簽章／發布 3）；Agent 約 40 分（verify 5、build 30、package 6）。
35. **Agent ② 直接部署跑通**：pipeline 3030035264（`feature/FR-172`＝`2d936a2`，target e2e，約 19 分：build 16、部署 3）。190 Agent 容器 `guidant-ai-agent:1.6.0` healthy；啟動防竄改「完整性驗證通過（249 個檔案）」；mTLS 8443 起來；心跳打主系統 200；主系統 `remote_agents` 看到 `agent_version=1.6.0`、`last_seen_at` 11:19；主控台 8444 有回應。等於 Agent 1.6.0 的套件升級（cryptography 50、PyJWT 2.15、flask-cors 6、opentelemetry 1.45）在真機上跟主系統握手過。系統說明三條路驗證表 Agent ② 可標已驗。

✅ 文件首腦已依第五批更新系統說明（`2c4faea03`）。Agent ② 直接部署在系統說明寫「實跑中」，結果補上後再更新。

**📗 文件首腦交棒（2026-11-05 中午）——下一棒文件首腦從這段開始讀**

本棒（文件首腦，2026-11-04～05）做完的：`writing-technical-docs` skill；設計 `design-v2.0.md` 定稿並收齊 CI 首腦第 1～27 點；系統說明 `docs/system-design/release-pipeline/出版管線總覽.md` 照 v2.0 重寫、再收第五批（`ee94f1473`、`2c4faea03`）。詳見 LOG「文件首腦」block。

下一棒兩件事，**讀完盤點完先回報、等決策者發令再動手**：

**A. FR-173 文件收尾（小）**
1. 系統說明：檔頭狀態、§2.1 Agent 直接部署「實跑中」改成實跑紀錄（第 35 點：pipeline 3030035264、約 19 分＝build 16＋部署 3、190 Agent 1.6.0 healthy、防竄改驗證通過、mTLS 與心跳正常）。
2. 系統說明 §4.4、設計 v2.0 §6.4 的「主機帶授權檔與機器指紋」不精確：實際送的是 **更新站身分票（`update_ticket`，License Center 另簽，只含授權編號、指紋、主版號、kid，不含客戶名稱；D9）**，沒有票的舊主機才送授權檔原文。來源：BE `app/product_update/service/update_site_client.py` `_identity`、`product_update_flow.py` `_host_identity`；update-center `src/licenses.ts` 檔頭、`src/routes/client.ts` `authenticate`（驗章 → 比對指紋 → 查拒絕名單 `license_denied`；不看授權到期日）。兩處都改。
3. 之後 CI 首腦若再發「📨 第六批」，照同樣方式對齊。

**B. 更新站系統說明（新，主工作）**——決策者 11-05 要求
- **為什麼**：更新站（update-center，Cloudflare Worker＋D1＋R2）是長期維運的獨立系統，但說明只散在 FR-167 需求站的 `update-site-spec.md`（Worker 規格與架構，410 行）、`update-site-schema-spec.md`（D1 資料表，329 行），兩份都停在 2026-11-01，沒有 FR-173 的改動；開頭還寫「轉交決策者在自己電腦簽好的清單」，已不是現況。update-center repo 只有 `README.md`（72 行，開發者筆記）與 `cli/README.md`（簽章 CLI）。
- **做法（文件首腦建議、決策者已同意方向）**：新開 `docs/system-design/update-center/`（比照 `release-pipeline/`：`README.md` front matter＋主文件＋`diagrams/`），照 `writing-technical-docs` 系統說明骨架，**以 update-center repo `feature/FR-172` 現行程式碼為準**重寫。FR-167 兩份原檔不動（FR 歷史），只在 FR-167 站 README 補一行指到新文件。update-center repo 的 README／cli README 留原地當開發者入口，主文件連過去。
- **決策者指定必須涵蓋**：①**每一支 API 的用途與流程**（客戶端 `/v1/check`、`/v1/download-url`、`/v1/report`、`/healthz`；後台 `/admin/*` 共 21 條路由，`src/routes/admin.ts` 的路由表）：每支寫誰呼叫、身分（授權／身分票、Cloudflare Access、CI token、GitLab ID token、Access 服務憑證）、request／response 欄位、錯誤碼、主要流程畫循序圖；②**資料表 schema**（`migrations/0001～0006.sql`，10 個 CREATE TABLE，含 `internal_hosts`、`product` 欄、`agent_version_reports`）：每張表欄位、鍵、誰寫誰讀；③**專案架構**（`src/` 各檔責任、`cli/` 簽章工具、`public/admin.html` 後台、`wrangler.toml` 綁定、部署方式、環境變數名稱——值不寫）。
- 骨架對應：概述 → 系統架構（元件圖、專案結構）→ 作業程序（部署、登記印章、維護內部主機清單、撤回）→ API 說明（客戶端、後台各一節）→ 核心機制（身分驗證、草稿可見性、發布檢查、版號排序含 `-beta.N`、預簽下載）→ 資料表 → 組態與機敏資訊 → 已知限制 → 故障排除（錯誤碼對照）→ 重建。
- 參考：FR-167 `update-site-spec.md`、`update-site-schema-spec.md`、`update-center-api-spec.md`（主系統端，只引用不重寫）；FR-173 `design-v2.0.md` §4.3～4.8、§6；出版管線系統說明 §4.3、§4.4、§6.3。
- 交付前照 skill 自檢（grep 口語／沿革、無純表格節、headless 截圖數 mermaid svg＝圖數、0 error）。改完 `python3 scripts/deliverables/render_index.py --site-root docs/system-design/update-center docs/system-design/update-center`。

**紀律**：只改文件，不碰 update-center 程式、Worker 部署、D1、更新站後台；查 `wrangler.toml`、`.env` 只印有沒有、鍵名、長度，不印值；系統說明本文不寫 commit hash 與沿革；顯式 `git add`；push 前 fetch 確認 CI 首腦沒有新 commit；對決策者回報一律白話。

**📨 第六批（2026-11-05 下午，跨版演練第一次實跑）——文件首腦照這批改系統說明**

36. **主系統跨版演練跑通（以 POC 為來源）**：1.27.10 → 1.29.0，來源 189 POC（正在跑 1.27.10，起點與資料同版）唯讀 pg_dump 56M。188 執行 `REHEARSE_SOURCE=poc scripts/build/deploy_e2e.sh 1.29.0 e2e --base-version 1.27.10`（不經 CI、不進版號、不發布），約 18 分。④ 清 190 → ⑤ 全新裝 1.27.10 → ⑥ dump 先灌空的參照庫數筆數、再 drop／create 灌 guidant_ai，**202 張表逐表一致** → ⑦ `install.sh --upgrade` 1.29.0 → ⑧ healthy、health true、四表筆數不變。首腦另外直接查：190 租戶與授權和 POC 完全一樣（租戶 1、3；授權在租戶 3 且租戶存在）、schema_migrations 478 → 486、9 個容器 healthy、前門 200、版本 1.29.0。log：188 `/home/jedi/rehearse-poc-1.27.10-to-1.29.0-20261105-1501-r3.log`。**更正**：同一天稍早以 STG 為來源的「1.28.0 → 1.29.0 通過」（`…-1305-r2.log`）**不算數**——灌庫漏表（見 37b），190 上租戶 3 不見、授權開通被 RLS 拒寫。
37. **演練與直接部署腳本的假綠 bug（已修，排錯表要收）**：第一次演練印「✔ 跨版排練通過」，實際只做到裝 1.28.0——⑥ 灌庫、⑦ 升級、⑧ 驗證一行都沒跑。根因：遠端腳本用 `… | ssh host bash -s` 經 stdin 傳過去，途中 `install.sh` 也讀 stdin，把剩下的腳本吃掉，遠端 bash 讀到 EOF 以 0 結束，本機看 0 就印通過。直接部署 `deploy_e2e.sh` 同一寫法同一風險。修法（BE `44ecc8286`）：`deploy_health.sh` 新增 `run_remote_script`——腳本存檔、scp 到目標機、`bash 檔案 </dev/null` 執行，最後一行必須是 `__REMOTE_SCRIPT_DONE__` 才算跑完；兩支都改用它。對 190 實測四種情境（正常／中途讀 stdin／中途 exit 0／非 0）判斷全對。**影響**：正式發版勾 `rehearse` 走同一支腳本，修前會假綠後照樣簽章發布。系統說明排錯表：症狀「演練印通過但升級前後筆數那幾行沒出現」→ 原因與修法如上；判讀規則「演練 log 倒數第二行必須是 `__REMOTE_SCRIPT_DONE__`」。
37b. **演練灌庫與起點的三個錯（已修，排錯表要收）**：① **灌庫疊在安裝好的庫上**：`pg_restore --clean` 在 install.sh 建好的庫上，外鍵讓表刪不掉（`cannot drop constraint tenants_pkey … other objects depend on it`），部分表留安裝預設值；腳本只印「有警告」繼續，驗證只比升級前後（前後一樣錯）→ 通過。症狀：演練後 190 開通授權 `new row violates row-level security policy for table "tenant_licenses"`（授權指到不存在的租戶 3）。修：drop／create＋`--exit-on-error`＋逐表筆數對「同一個 dump 灌進空庫」（BE `df6bec311`、`0e1081bd8`）。不可對活的來源庫數筆數：POC 一直在寫，dump 與 count 不同時點，`api_logs` 差 2 筆就紅（實踩）。② **起點與來源不同版**：STG 跑 1.27.8，演練卻裝 1.28.0 再灌 1.27.8 的資料。修：`REHEARSE_SOURCE=stg|poc`，起點必須等於來源機 guidant-api 版本，不符拒跑（`df6bec311`）。③ **升級過的機器清不乾淨**：資料庫已改在 `GUIDANT_PGDATA_DIR`（bind），`down -v` 刪不到舊的 named volume `guidant_guidant-pgdata`，install.sh 看到「有舊庫沒 .env」拒裝。修：再刪 compose 專案標籤 guidant 的 volume（Agent 的不同專案不受影響，`d6d2fa573`）。
38. **演練會清掉 190 整套主系統，Agent 因此斷線**（作業程序要寫的副作用）：演練 ④ 是 `compose down -v`＋刪 `pki/`、`.env` 等，重裝後主系統的 HTTPS 憑證與 Agent 對接金鑰都是新的。190 上的 Agent（1.6.0，Agent stack 不在清除範圍、容器照跑）心跳失敗：`CERTIFICATE_VERIFY_FAILED … 雲端憑證與安裝時確認過的那一份不符`；主系統 `remote_agents` 是來源機（現為 POC）的資料、沒有 190 Agent 那一列。要接回去得在 190 Agent 重新執行安裝確認指紋並重新註冊（主系統先產註冊 token）。系統說明演練段要寫：演練後 190 上的 Agent 要重新註冊；190 主系統的資料會變成來源機（STG 或 POC）的，含它的使用者與整合憑證。
39. **Agent 演練未跑**：188 沒有 Agent 樣本 db（`.build/rehearse/agent-<舊版>.db`），而 190 現在的 Agent 是 1.6.0，拿它的資料當 1.5.5 起點不合理。決策者裁先不跑。要跑得先在 190 裝回 1.5.5、產生資料、匯出樣本。
40. **演練預設起點與來源**：主系統 `rehearse_base` 預設 1.27.0，188 沒有那個包；起點要等於來源機版本（目前 STG 1.27.8 包已刪、POC 1.27.10 有包）。預設值與來源政策交 R-2（CM-3499）與決策者。
41. **第五輪 8 張卡已開（CM-3498～3505，母卡 CM-3462，批 6～8）**：拆卡表 `handoff/cards_r5.py`、產卡 `gen_notion_cards_r5.py`、建卡結果 `notion-cards-r5-made.json`。批 6：R-3 演練驗證加深與可重跑（3500）、R-4 正式包與內部包分開（3501）、R-5 190 互斥鎖（3502）；批 7：R-1 演練升級改走更新中心（3498，依賴 R-3）、R-2 有 migration 就強制演練／起點／必經版本（3499）、A-5 Agent 用 190 鎖＋正式包另存＋自動留演練樣本（3503，依賴 R-5）；批 8：C-5 正式發版第一步預檢（3504，依賴 R-2）、C-6 每日掃映像＋弱掃平行（3505）。卡上帶「190 例外」：要在 190 實跑驗的卡（R-1／3／4／5、A-5）只准動 190，188 只讀、189 只唯讀 dump。不開卡、等決策者：專用演練機、演練來源政策、FE `v*` 受保護 tag、188 docker 建置快取清理。

42. **批 6、批 7 進度（2026-11-05 晚）**：批 6 R-3／R-4／R-5（CM-3500～3502）與批 7 R-2（3499）、R-6（3506，R-4 改了內部包位置後讀包路徑的補卡）、A-5（3503）皆「驗收通過待確認」，已推（BE `7cfee7aeb`、Agent `97b2e9c`），188 兩個工作樹已同步；批 7 R-1（3498）跑中。**R-2 改了產品行為（要記進下一版版本說明）**：manifest 把 **1.28.0 標成必經版本**，1.29.0 起出的包「可直升起始版」是 1.28.0（不再是 1.0.0）——1.28.0 是第一個帶 Vault 正式章公鑰的版本，低於它的機器本來就驗不過 1.29.0 的章。影響：**STG（1.27.8）、POC（1.27.10）都要先升到 1.28.x**，也不能再拿它們當演練來源（演練閘會擋起點低於 1.28.0）。下午那次「POC 1.27.10 → 1.29.0 演練通過」驗的是 1.29.0 包內舊的 min_base（1.0.0），客戶實際路徑要經 1.28.0。R-6 合回前（`f0d2731ef`～`7cfee7aeb` 之間）直接部署與測試版發布找不到內部包——已解。

**🔴 此刻（2026-11-05 22:00）——CI 首腦第 4 棒交棒（context 快滿）**

**下一棒先處理**：
1. **R-1（CM-3498）沒卡住、已交件**（第 5 棒 22:30 更正下面第 4 棒的判斷）：runner 在寫 254 行的新腳本，21:5x commit `a5ad4c376`（6 檔）、卡改修正待驗證。第 5 棒核過：bats 26 條本機重跑全過、測試章 kid 重算對得上、190 全 healthy／`guidant.env` 多一行 `UPDATE_SITE_URL`／臨時帳號 0 筆。**沒驗到的**：190 完整八步（需先 `pipeline=test-release` 發一個比 1.29.0 大的 beta，例 `1.29.1-beta.1`，再 `REHEARSE_DRAFT=existing` 跑演練；且來源機要是 1.28.x 才過 R-2 的必經版本閘）。**決策者裁兩件（22:40）**：① `REHEARSE_VIA` 預設改回 `install`（正式發版演練版號是正式格式、release-ci 簽不了測試章，預設 update-center 一勾演練就紅；`release.yml` 是批 8 C-5 的檔不能動）——已給 runner prompt 補，等他 commit 後驗收；② 188 `.build/release-archive/` 原本不存在（R-4 合回後沒出過正式版，演練會找不到起點），第 5 棒已把 1.27.10／1.28.0／1.29.0 各 5 檔（tar.gz、ops、兩個 sha256、release.json）從 `bundle/` 複製進去、sha256 全對，188 剩 81G。
   第 4 棒原判斷（保留）：工作坊 runner session `CM-3462-CM-3498` 狀態 busy 但 1 小時零產出——工作樹 `.worktrees/CM-3462-CM-3498` HEAD 仍是 `f0d2731ef`、無 commit、無未提交改動；188／190 上也沒在跑東西；決策者傳訊它也沒回。推測卡在卡上「測試章登記草稿要 Vault `test-ci`，CI 外拿不到 ID token」那段。建議：決策者停掉那個 session（工作坊狀態頁），R-1 拆小——這張只做到「腳本寫好、`deploy_rehearse.sh` ⑦ 可選 `REHEARSE_VIA=update-center`、bats 過、能在 CI 跑」，190 實跑改成下一次測試版發布或正式發版勾 rehearse 時順驗；或首腦判斷 CI 外取得測試章的正確做法後在卡上 append。R-1 未合回前不影響其他東西（它只動 `deploy_rehearse.sh` ⑦ 與一支新檔）。
2. **批 8 已派、已驗收、已合回推上（第 5 棒 23:30）**：C-6（CM-3505）`6d009bc41` 工作坊自動合；C-5（CM-3504）`5421576bf` 與 C-6 在 `sbom.sh scan_image` 撞檔（C-6 改平行、C-5 加 `dir:` 來源），首腦合成一段（平行結構＋`$trivy_mode`／`$src`）。合回後 bats 54 條、守衛 119 passed、四支 CI yaml 解析過，188 已 pull 到 `5421576bf`。**第五輪 8 張工程卡全部收完。** 兩件等真 pipeline 首次實跑：正式發版 verify 第一步預檢（更新站 GET `/admin/keys`／`/admin/releases/<版>` 對 CI token 回 403，預檢只警告；要擋得更新站開放這兩支 GET）、每日排程的 `scan-latest-images`。
3. **R-2 把 1.28.0 標成必經版本**：下一版版本說明要寫；STG（1.27.8）、POC（1.27.10）要先升 1.28.x（POC 升級要決策者放行）。
4. **190**：主系統 1.29.0（資料是 POC 的，R-3 小弟 18:39 又演練過一次）；Agent 1.6.0 已重新註冊（新 uid `2f7d0bb9-…`），主系統端 16:30 時是 `pending`，**決策者要在 190「檢測 Agent 管理」按核准**（之後若又演練，會再斷、要再註冊）。
5. **188**：11-05 清到 93G（建置快取 >6h 與 24 個舊映像標籤，保留 1.27.8／1.27.10／1.28.0／1.29.0、Agent 1.5.0／1.5.5／1.6.0）；BE 工作樹 `7cfee7aeb`、Agent `97b2e9c`。

**決策者提的新需求（還沒開卡，等 CI 做完再討論、開新 FR）**：
- 主系統可主動叫 Agent 同步：核准時順推 `config/notify`、Agent 管理頁加「立即同步」，不必等 5 分鐘心跳。用既有直推（8443 `POST /config/notify`），不新開路；要先查核准前推指令會不會被 Agent 身分驗證擋。
- Agent 首次設定改網頁：安裝不問問題，裝完瀏覽器開 8444 未註冊時直接填主系統網址＋token（不用登入），註冊後才走正常登入。動機：一線安裝人員多非 IT。安全要擋「搶先註冊」——首腦建議主系統產 token 時登記 Agent IP、Agent 只接受對得上的；token 可帶主系統憑證指紋免人比對；註冊後首頁明顯顯示已註冊到哪。重新註冊（`re-enroll`）也走同一個精靈。
- 189 License Center gunicorn `-w 2` 同步 worker 會被長連線佔滿（11-05 下午 188／190 連 5062 間歇逾時、自行恢復）；改 `--threads` 要動 POC，等裁示。

**以下是 2026-11-05 下午的此刻（保留參考）**

**三條路驗到哪**：
| | 主系統 | Agent |
|---|---|---|
| ② 直接部署 | ✅ 3025779481、3026701936（190） | ✅ 3030035264（190，1.6.0 內容；心跳、mTLS、主系統看到在線） |
| ③ 測試版發布 | ✅ 3026010775（1.28.4） | ✅ 3026549240（1.5.6-beta.1） |
| ① 正式發版 | ✅ **1.29.0 已發布**（3027235959） | ✅ **1.6.0 已發布**（3029934137） |
| 正式章簽的包在客戶機驗章升級 | ✅ 190 1.28.4 → 1.29.0 | ⏳ 走直接部署（不驗章）；Agent 從更新中心升正式版留到下一版 |
| 演練 rehearse | ✅ 1.27.10 → 1.29.0 帶 POC 資料、202 表逐表一致（188 直接執行腳本，第六批 36） | ❌ 沒跑過（188 沒樣本 db；A-5 會自動留） |

**190**：主系統 **1.29.0**，資料是 **POC 的**（演練後；租戶 1、3，授權 lic-5828a0b1220b 在租戶 3）；Agent 1.6.0 容器在跑但**心跳失敗**（演練重裝換了主系統憑證與對接金鑰，要在 190 重新註冊，第六批 38）。**188**：BE 工作樹 `feature/FR-172`（`0e1081bd8` 以後）；剩約 15G，**下一次建置前要清**（docker 建置快取約 40G 可回收，等決策者）。

**GitLab 畫面標 failed 但 job 全綠**：Cloudflare Pages webhook 把文件站建置狀態掛到 commit 上；成敗看 job 清單。之後可在 Cloudflare 停掉或加 branch 過濾（決策者決定）。

**待辦**：工程項目都在第五輪卡上（第六批 41，CM-3498～3505）；決策者要裁的：專用演練機（演練會清 190、與 demo 互相干擾）、演練資料來源政策（STG／POC）、FE `v*` 設受保護 tag、188 docker 建置快取與舊映像標籤清理、190 Agent 重新註冊、189 License Center gunicorn `-w 2` 同步 worker 會被長連線佔滿（11-05 下午 188／190 連 189:5062 間歇逾時，自行恢復；改 `--threads` 要動 POC，等裁示）。

## §4 待辦與風險

- ✅ **2026-11-04 傍晚實跑結果（主系統）**：② 直接部署 190（3025779481）成功；③ 測試版發布 1.28.4（3026010775）登記草稿＋上 R2 成功，190 從更新中心按更新 → 下載 3.3GB → 測試章驗章 → 八步升級 succeeded，190 現為 1.28.4、全部容器 healthy。更新站 `instance_version_reports` 的 `current_version` 已是 1.28.4，但 `last_upgrade_*` 仍是舊的（1.28.1→1.28.2），升級結果回報可能下次檢查才送——**下次回來先核**；三台同指紋讓這張表有多列互蓋，判讀不準（見 machine-id 那條）。Agent 三條路尚未實跑。下一步：放行批 6（CM-3494／3495 預發版號）→ Agent 直接部署與測試版發布實跑。
- ✅ **CI 打更新站 `/admin/*` 被 Cloudflare Access 302**（2026-11-04 撞到、當天解）：決策者裁用 Service Token（不用 Bypass），Access 應用程式加「服務驗證」原則 `guidant-ci`，憑證存 Vault `kv/ci/update-site`；BE／Agent `publish_draft.sh` 帶 `CF-Access-Client-*` header。**Service Token 有到期日**（決策者建立時選的期限），到期 CI 會再 302，要在 Access 後台換新並更新 Vault 兩欄。
- 🔴 **內部三台 `/etc/machine-id` 相同**（2026-11-04 首腦登內部主機清單時發現）：190／188／189 是同一範本複製的 VM，`sha256(machine-id)`＝主機指紋三台都是 `ff793254…a080`。更新站、授權綁定、Agent 心跳的主機身分都用它，三台在更新站眼裡是同一台：內部主機清單登一筆即三台都認（這次反而方便），但 `instance_version_reports` 以 (license_id, fingerprint) 為鍵，三台升級回報會互蓋。決策者裁：先不動、跑完今天驗證；**1.29 正式出版前另開卡重生三台 machine-id**（`systemd-machine-id-setup`），要同時重簽三台授權（綁指紋）、更新站內部主機清單改成三筆，排在沒人用 STG／POC 的時段。
- **已裁（11-03）**：出包時就蓋章、GitLab job 身分發布（V-1 擴大到 Worker）、測試包模式＋Vault 測試章 `guidant-test`；發版起點是 GitLab Run pipeline。
- **GitLab 免費版限制（已補進卡）**：`secrets:`、`needs:project` 都是付費版；改 `id_tokens`＋script 內登入 Vault、`CI_JOB_TOKEN` 打 API 拿 artifact。`trigger:` 跨專案免費版可用，用 `strategy: mirror`。
- **runner 現況**：188 shell runner（id 56998011，tag `guidantai-build`，群組級 auditmanager）；docker runner 只有一台（id 37407054，tag `docker`，17.0.0，只註冊給 FE 專案，不在 188，主機待決策者確認）。jedi 套件在 `commonservice3` 群組，沒有可用 runner。

- **11-03 出包腳本變動（FR-172 收尾，已推 `feature/FR-172`；C-1／C-2 開工前要知道）**：
  - BE `scripts/build/build_all.sh`：帶 `--skip-prod-key-check` 時略過 ⓪a、⑦ 兩次 SBOM／弱點掃描（`09308ef5d`）。CI rehearse 段直接呼叫 `build_bundle.sh`、不經 `build_all.sh`，不受影響；package 段照舊全掃。
  - BE `scripts/build/build_bundle.sh`：封包改 `tar | pigz`（沒裝退回 gzip，`09308ef5d`）；釘版第三方 image 的 `docker save` 檔以 image ID 快取在 `.build/image-cache/`（`9c1539491`）。CI runner 每次乾淨工作區的話快取不生效，要生效得把 `.build/image-cache/` 放在 runner 的持久目錄。
  - Agent `scripts/build/build_all.sh`／`build_compose_bundle.sh`：新增 `--internal-test`（略過 Step 3b 弱點關卡，`70ec3d2`）；seaweedfs 匯出檔快取（`cd3a1f9`）。C-2「`build_all.sh` 加 CI 模式旗標」要與它併用，不要另開一個意思相同的旗標。
  - 實測（188）：Agent 包 `--internal-test` 15 分 52 秒（原 19 分 30 秒）；主系統完整 build 51 分，其中 Nuitka 約 19 分、封包壓縮約 13 分、SBOM＋弱點掃描約 9 分。Nuitka 在 188 本來就沒開 LTO，`--lto=no` 無效。
- **測試期手動出版仍在用**：Mac `~/Projects/Billows/Audit-Manager/.fr167-dev/publish/publish2.sh host|agent <版>`（測試章簽、R2＋D1，不入版控）。1.28.x 正式版不出，正式章／Vault 簽的第一版是 1.29（本案）。
- 🔴 **Vault 沒快照**：172 壞了這把章就沒了（Mac 備用章還在，但要出一版換 kid）。
- 188 `/opt/jedi-python-package` 原本的 git 網址內嵌一把 GitLab 個人 token（`glpat-`），2026-11-03 曾印進對話紀錄。**已處理**：188 改走部署金鑰 `Build-188-STG`（唯讀）、決策者已撤銷那把 token、本 session 與另一個 BE session 的對話紀錄檔已就地遮掉。
- 舊對話歸檔（BE repo `docs/conversation-history/` 6 份、`security-scan-consolidated` 1 份，2026-04～05）與 FE 兩份對話紀錄裡另有 `glpat-` token（非這次那把），待決策者確認是否已撤銷。
- Harbor 帳密 `kv/ci/harbor` 是共用的一組，能推 `guidant-ai` 專案底下任何映像、任何 tag。`test-ci`、`classifier-ci` 都不綁 ref（決策者按的任何 branch 都拿得到），所以決策者在別人推的 branch 上按測試包或觸發 jedi，那個 branch 的程式碼就能推（或蓋掉）Harbor 上任何映像。資安自動檢查 2026-11-04 提出（通用的最小權限建議，**不是**本專案 `.claude/rules/security/` 或 SR 的要求）。決策者裁：先不處理，每個映像一個帳號太多。日後要補，優先只開 Harbor `guidant-ai` 專案的 tag 不可覆寫（一個設定，擋住既有版本被蓋掉；我們推的 tag 都帶 commit，不影響流程），不建 robot 帳號。
- 🔴 V-1 `publishSignedDraft` 寫入只核對 kid：檢查到寫入之間同 kid 換包會發布 190 沒裝過的包。修法：WHERE 加 sha256、signed_manifest。正式模式「發布」實跑前要修（CM-3463 卡尾）。
- 188 兩個 GitLab runner 的認證 token（`glrt-`）2026-11-03 曾印進對話紀錄，**已重設**（`gitlab-runner reset-token --all-runners`，舊 token 失效）。**歸檔對話時仍把 `glrt-` 開頭字串遮掉**。GitLab 網頁沒有重設 runner token 的按鈕，以後要換一律在 188 跑這行。
- 第一個 root token 曾貼進對話紀錄（已撤銷、失效）；兩個 jedi token 也曾貼出（已撤銷）。**歸檔這段對話時要把 `hvs.` 開頭的字串遮掉。**
- `vault-ca.key` 還在 172 `/opt/vault/tls/`，手冊建議複製到保管處後刪除，決策者未做。
- 只有一個管理員：Apple ID 單獨湊得滿 3 把解封鑰匙；有第二人時重分。

## §5 Pre-flight（唯讀）

```bash
# 三個 repo 都在 feature/FR-172、本機＝遠端
for r in compliance-manager-be compliance-manager-fe evidence-agent; do d=~/Projects/Billows/Audit-Manager/$r; git -C $d fetch -q --tags origin; echo "$r $(git -C $d branch --show-current) ahead=$(git -C $d rev-list --count origin/feature/FR-172..HEAD) behind=$(git -C $d rev-list --count HEAD..origin/feature/FR-172)"; done
# 更新站最新幾筆（host 1.30.1、agent 1.7.0 應為 published；agent 1.7.1 不該出現）
cd ~/Projects/Billows/Audit-Manager/update-center && npx wrangler d1 execute guidant-update-center --remote --json --command "SELECT product,version,status,kid FROM product_releases ORDER BY created_at DESC LIMIT 6"
# 188 空間、編譯鎖、BE 工作樹（Agent 弱點關卡讀它的白名單）
ssh jedi@192.168.50.188 'df -h / | tail -1; pgrep -af "build_release|nuitka|build_all" | grep -v pgrep | head -1; git -C /opt/guidant-ai-be log --oneline -1'
# FR-185 子卡狀態（下一版的範圍）
python3 /Users/chouraymond/Projects/Jedicogy/agent-workshop/scripts/notion_case.py get https://app.notion.com/p/412346da4cd0816583a6f1a9ceeafd5c
```

## §6 環境座標

- Vault：`https://192.168.50.172:8200`（網頁 `/ui`，登入方式 Username）；SSH `jedi@192.168.50.172`，sudo 要密碼。
- CA 公開憑證：172 `/etc/vault.d/vault-ca.pem`。
- 手冊 `vault-setup-runbook.md`、現況 `vault-status.md`。

## §7 行為規範提醒

- 祕密（解封鑰匙、root token、jedi 密碼、任何 `hvs.` 字串）不進文件、不貼 Notion、不進 repo。
- 172 上的操作由決策者自己登入做；首腦只唯讀查（不帶 token 的 `vault status`、或決策者已登入留下的 token 做唯讀 lookup）。
