# 首腦交接：v1.20.0 出版後（2026-09-15）

> 前一個 arc（FR-089／090／091／093／094）**已完整收尾**，五張母卡全收、SUMMARY 落地。
> 本檔交接的是**出版後的收尾殘項**，不是未完成的 arc。
> arc 全文見 `docs/features/FR-089-2609-package-shape-unification/handoff/2026-09-15-arc-SUMMARY.md`。

## §0 接手讀序

1. 本檔全部（不長）
2. `2026-09-15-arc-SUMMARY.md` §「已知 follow-up」與§「交付包注意」兩段
3. 需要細節才開：`FR-089-LOG.md` 最後兩個 block（第十二任、第十三任）

### 冷接自檢（答得出來才開工）

1. v1.20.0 已經出版了，為什麼還要重出一次包？
   （答：CM-1807 三支套件修正發版後，主專案 pin 跟著改，內容與原本打 tag 那顆不同。決策者裁「還沒給客戶，就用 1.20.0 不跳號」。）
2. 為什麼主專案的 DI 改動一度是個隱患？
   （答：`b70cc44a` 在 DI 傳 `identity=` 給 SurveyFolderService，但 Nexus 上的 jedi-survey 1.1.1 建構子不收這參數——乾淨環境 `poetry install` 後啟動會 TypeError。本機看似正常只因 `.venv` 讀的是工作樹。發 1.1.2 ＋ 改 pin 後解除。）
3. 這個專案為什麼不能裸跑 `poetry update`？
   （答：不帶套件名會更新整棵相依樹，2026-09-15 順手升了 faker／google-api-python-client／pytest-html 等四支第三方套件——那些沒人驗過卻會進安裝包。一律 `poetry update <指定套件>`。）
4. 套件在 `poetry.lock` 裡是 wheel 還是源碼樹？為什麼重要？
   （答：**wheel**。Nuitka 編譯吃 wheel 是 build 加速的前提，不可改成 path 形式。`pyproject.toml` 裡的 path override 全是註解狀態，開發期臨時打開後**不可 commit**。）

## §1 當前狀態（2026-09-15 傍晚）

### 三 repo

| repo | branch | HEAD | 與遠端 |
|---|---|---|---|
| BE | `main` | `cc16f56d` pin 三支套件 | 已推 |
| jedi | `main` | `8bc5d27` 三支套件進版 | 已推 |
| FE | `main` | `6670c5f` 版號對齊 1.20.0 | 已推 |

### 版號

- 主專案 **1.20.0**（正式版）、FE **1.20.0**
- jedi 21 支：多數 1.1.0；**1.1.1**＝task-platform／compliance-audit／system-core／issue；**1.1.2**＝common／iam／file-upload／notification／flow-engine／log／remote-agent／survey；oscal-v2 走自身序列 2.4.0
- 全數已推 Nexus

### 🔴 tag 狀態（**接手第一件要處理的事**）

遠端 BE／FE 都有 `v1.20.0`，但**指向的是舊 commit**（BE `34d48807`），那時還沒有 CM-1807 的三支套件修正。

決策者已裁「刪掉再打一次就好」。**等 190 手測通過後**執行：
```bash
# BE
git tag -d v1.20.0 && git push origin :refs/tags/v1.20.0
git tag v1.20.0 && git push origin v1.20.0   # 推 tag 要決策者明示
# FE 同理
```

### 190 部署狀態（已完成）

**1.20.0 正式版已裝上 190**，六服務健康（`guidant-api`／`socketio`／`fe` 皆 `1.20.0`）。
升級腳本自動備份了資料庫：`/srv/guidant-ai/backup/guidant_ai-pre-1.20.0b2-20260915-174612.sql.gz`（3.9M）。

產物驗過（README 規則，從編譯後二進位 grep）：`get_menu_by_id` 3 處、`created_user_name` 131 處、
`GRC_403064` 2 處、**`get_manu_by_uid` 0 處**（壞方法確實刪乾淨）。

🔴 **190 的 MFA 目前是開著的**（決策者測試時打開），而 MFA 有缺陷（見下），
**該環境登出後會登不回去**。要用 190 做其他驗證前，先把 MFA 關掉：
改資料庫 `system_configs` 的 `MFA_REQUIRED`，或請決策者在畫面上關。

### Notion 卡

| 卡 | 狀態 |
|---|---|
| 五張母卡（1688／1682／1690／1752／1766） | ✅ Done |
| 六張實作子卡 | ✅ Done |
| **CM-1807** | 修正待驗證，**等決策者在 190 驗過才收** |
| 資安掃描 25 張 | 修正待驗證（**另一個 session 的 arc，不要碰**） |

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

| 裁示 | 何時 |
|---|---|
| 還沒給客戶，重出包**用 1.20.0 不跳號**，tag 刪掉重打 | 2026-09-15 |
| 除了本次修正的東西，**其他外部套件都不要動** | 2026-09-15 |
| 角色矩陣**不顯示「原廠保留」標籤與 hover 提示**，只保留不可勾 | 2026-09-15 |
| 簡體中文錯誤訊息翻譯**不補** | 2026-09-15 |
| 跳過自動回歸測試，以 190 實機手測為準 | 2026-09-15 |
| 188 舊交付包**只留 tar.gz**，刪掉解開的目錄 | 2026-09-15 |
| 資安掃描結果的修正**不進 1.20.0**，另開 arc | 2026-09-13 |

## §2.5 🔴 出版後發現的缺陷：MFA 開啟後登不進去（CM-1808）

決策者 2026-09-15 在 190 開啟 MFA（多因素驗證）後，登入第二關輸入驗證碼送出**回 500**。

**根因已查明（不必重查）**：`jedi-iam/jedi_iam/api/routes/otp_route.py:127` 的
「發 token」那一段沒有包提權，而 FR-094 把租戶隔離改成 fail-closed 之後，
登入第二關還沒有身分 → 什麼都查不到 → 下游取 `login_name` 拿到 None 就炸。
同檔 117 行的「查人」那段**有**包提權（`_lookup_user_before_login`），所以是漏了一段不是整支沒做。

**不是 1.20.0 這次改動造成的** —— beta.1／beta.2 就存在，只是當時沒開 MFA 沒人走到。
時間點指向 `fc1cadb`（FR-094.1c／CM-1788「引導型與機器端點接上顯式身分」），那一棒漏了發 token 這段。

**修法要先判斷**（卡上寫了兩案與首腦傾向，但沒實查過可行性，交接方自行決定）：
擴大提權範圍（最小改動但拉大繞過隔離的範圍）vs 驗證成功後先設好身分再發 token（較乾淨）。

卡：**CM-1808** https://app.notion.com/p/MFA-500-fail-closed-token-190-3dc346da4cd0814aaa87e1f4005b69bf

## §3 下一步（每項都要決策者發令）

0. **派 CM-1808**（MFA 缺陷，建議 Opus medium——根因已查明但修法要設計判斷）
1. **決策者在 190 手測八件**（清單見 §4），通過後：
2. **收 CM-1807**（改 Done）
3. **刪遠端舊 tag 重打 v1.20.0**（見 §1）
4. **上 STG（188）→ POC（189）**——照 release note 第 7 節順序，POC 等同 production
5. **待決策者裁**：資安總表 12 項哪些要修／四支 audit-round 端點要不要退役

## §4 190 手測清單（八件）

網址 `https://192.168.50.190`。**先強制重新整理瀏覽器**（Cmd+Shift+R）。

🔴 **測之前先確認 MFA 是關的**（見 §2.5），否則登出後會登不回去。

**前五件是回歸確認**（beta.2 已測過）：
1. 子租戶管理員 → 新增角色 → 勾「合規框架」→ 存檔**應成功**，那一列只有「檢視」勾得到、**旁邊不該有任何標籤**
2. 最上層租戶管理員 → 同樣操作 → 四個動作**全部勾得到、存得起來**（改壞這邊比原本的 bug 更嚴重）
3. 最上層管理員但「隸屬租戶」選子租戶 → 那三個動作應**變成勾不到**
4. 停在專案詳細頁 → 切換租戶 → **應回到首頁**不報錯；切語系數次後租戶下拉**不該有重複項目**
5. 合規資源庫 → 新增 → 套用控制項 → 群組標題應為 `Access Control (4)`，**沒有 null**

**後三件是 CM-1807 新增**：
6. 問卷資料夾清單 → **建立者欄位應顯示暱稱**（例如「Billows Admin」）而非帳號
7. system-core 選單查詢：**沒有對外端點**，已由套件測試（241 passed）驗證
8. issue 查無成員：**沒有對外端點**，已做突變驗證（拿掉修法轉紅、還原轉綠）

## §5 環境座標

| 項目 | 值 |
|---|---|
| BE repo | `~/Projects/Billows/Audit-Manager/compliance-manager-be`，branch `main` |
| jedi monorepo | `~/Projects/Jedicogy/module/jedi-python-package`，branch `main` |
| FE repo | `~/Projects/Billows/Audit-Manager/compliance-manager-fe`，branch `main` |
| DEV DB | `localhost:5432` `guidant_ai_dev`，帳號 `cmmgr`，密碼查 `.env` |
| 190 e2e 測試機 | `https://192.168.50.190`，ssh `jedi@192.168.50.190`（有免密 sudo） |
| 188 build 機 | `/opt/guidant-ai-be`（BE）／`/opt/guidant-ai-fe`（FE），更新走 `git pull`，**禁 scp** |
| Notion CLI | `python3 scripts/notion_case.py get/status/append/query`；建卡 `scripts/notion_create_case.py` |

## §6 🔴 188 build 機的三個固定陷阱（每次都會撞）

**① `build_all.sh --all` 直接跑會被 DB 斷言擋下。**
預設連安裝版 stack 的 `guidant-db`——**那是 STG**，落後好幾支 migration。**不要去套 migration**（違反環境異動鐵律）。正確做法：
```bash
cd /opt/guidant-ai-be && PW=$(grep -m1 "^DB_PASSWORD" .env | cut -d= -f2-)
SMOKE_DB_TARGET=env DB_HOST=127.0.0.1 DB_PORT=25432 \
DB_NAME=guidant_ai_smoke_1200b1 DB_USER=cmmgr DB_PASSWORD=$PW \
scripts/build/build_all.sh --all
```

**② FE image 標籤可能與 BE 版號對不上**（beta 版才會，正式版兩邊同形不會）。
封包腳本按 **BE 版號**找三顆 image。build 過程那行「✔ 版號一致」**是綠的也沒用**——兩者比的不是同一個東西。撞到就 `docker tag guidant-ai-fe:<人看版號> guidant-ai-fe:<Python版號>`。

**③ 磁碟會滿。**
每出一版留約 3.3GB，build cache 不自動清。清法：`docker builder prune -f`（**不要加 `-a`**）；`.build/bundle/` 舊版**只刪解開的目錄、保留 `.tar.gz`**；刪 image 前先 `docker ps`——**188 上跑著 STG stack**。

**④ 出包後必驗產物**（README 規則）：
```bash
strings .build/dist/<版號>/guidant-ai | grep <該版新增的獨特字串>
```
回 0 就是沒進去。本次驗的是 `get_menu_by_id`（3 處）、`created_user_name`（131 處）、`GRC_403064`（2 處）、`get_manu_by_uid`（**0 處**＝壞方法確實刪乾淨）。

## §7 行為規範提醒

- **`poetry update` 一律指定套件名**，不要裸跑（見 §0 自檢第 3 題）
- **`poetry.lock` 裡套件是 wheel**，不可改成 path 形式（Nuitka 加速的前提）
- 不切 branch、不推 push（等決策者明示）、不碰 STG／POC
- **驗收不採信 runner 自報**：自己跑測試、開檔核對、必要時做突變驗證
- **推翻 runner 時分清「方向」還是「範圍」**——2026-09-15 CM-1807 第一項，runner 推翻了首腦卡片上的兩個選項且**他是對的**（那張表根本沒有 `uid` 欄位）
- **文件與 Notion 不一致時兩邊都不可信**，去查 `git log --grep` ＋ 開檔
- 回報一律白話文，術語首次出現要解釋
- 派工 prompt 薄（卡號＋URL＋一句範圍＋建議 model），細節進 Notion 卡

## §8 交付包注意

🔴 **目前的包缺正式環境（PROD）授權簽發公鑰**——尚未建立（非故障，套件內只有 dev／stg／poc 三把），封包時以 `--skip-prod-key-check` 略過。**因此不可交付客戶。**

要出可交付的包需另行四步：授權中心端產正式簽發鑰 → 加進 `jedi-license-runtime` 的公鑰表 → 發版 → 重新 build。**第一步不在開發端能做的範圍。**
