# 2026-07-25 資安 arc 全收官 + Sonar 存量清理 arc 開局 — 換 session Handoff

> ✓ **CLOSED — 2026-07-25 同日收官**:清理 arc 全案完成(CM-895~905 全 Done、兩 repo open 1,440→0、QG 雙綠),已進版 **v1.10.1**(tag 已推)。收官全貌見同目錄 `2026-07-25-v1.10.1-sonar-cleanup-arc-SUMMARY.md`。本文件僅供歷史參考。

| 項目 | 內容 |
|------|------|
| 緣由 | 資安 arc（2607）**全案終結**：全部 case Done、三工具帳面全零、Quality Gate 雙綠。同日 user（雷門）依 PM 要求開啟新 arc「Sonar 存量 code smell 清理」，已完成裁決 + accept 標記 + case 群開案，實作交下一棒 |
| Branch | BE / FE 皆 `main`，working tree 乾淨（BE 的 untracked 為既有已知項，與本 arc 無關） |
| 本棒角色 | 任務分析首腦（只派工不實作）：主 session 派 subagent + user 的外部 loop runner 並行 |
| 接手前必讀 | 本文件全讀 → 前一棒 handoff `2026-07-25-security-arc-final-session-handoff.md`（資安 arc 背景）→ Notion 搜「Sonar 存量清理」 |

## 🧭 原始需求 / WHY

**資安 arc（已終結）**：三工具（trivy/semgrep/SonarQube）掃描 BE+FE，HIGH/MEDIUM 歸零、憑證處置、剩餘項條條有歸屬——目標是掃描流程進 GitLab CI 前的乾淨基線。**本日達成：全零 + 存證**。

**新 arc（Sonar 存量清理，本 handoff 的主交接物）**：user 進 SonarQube 看到大量程式建議，**PM 要求盡量清掉**。2026-07-25 雷門裁決三級處置：
- **一級（機械性 ~700 條）→ 真清**，開 case 群給外部 runner
- **二級拆兩刀**：S8786 regex ReDoS ×44 + S5754 裸 except ×11 + S5886 回傳型別 ×18（**73 條真修**，需查證紀律）；S1172 ×80 / S107 ×37 / S7721 ×34（**154 條標 accept 緩做**，已標完）
- **三級（S3776 認知複雜度 ×236 + S3516 stub ×8）→ 不做**，「本來就是這樣」，已標 accept

**冷接自檢 4 問**（答得出再動工）：
① 三級 S3776 為什麼不修？（既有裁決禁區：重構 200+ 函式風險高於收益；S3516 是 FR-038 2A 刻意 stub，改真邏輯會出事、等 2B）
② 二級 154 條標 accept 的理由？（動函式簽名/作用域、無測試護航風險高——裁決緩做，不是永不做）
③ 「派 runner」是什麼意思？（user 的**外部 loop runner** session 接 Notion case 執行；主 session 只開 case 不 spawn subagent 做 runner 類 case——memory `feedback_runner_means_external_loop_runner`）
④ Quality Gate 現在是什麼策略？（Guidant-NewCode：只看 new code 零新增，存量不擋版；scanner 要帶 `-Dsonar.projectVersion` 讓 baseline 隨進版重置——見 `docs/features/security-scan-2607/sonar-quality-gate-setup.md`）

## §1 資安 arc 終結狀態（不需再動，僅存證）

**最終帳面（2026-07-25 第二輪基線掃描 + 尾巴收零後）**：
| 指標 | BE | FE |
|------|-----|-----|
| trivy vuln | 0（weasyprint 升 69.0 收掉最後一條） | 0 |
| semgrep ERROR+WARNING | 0 | 0 |
| Sonar OPEN VULN / hotspots | 0 / 0 | 0 / 0 |
| Sonar OPEN BUG | 0 | 0 |
| Quality Gate（Guidant-NewCode） | **PASSED** | **PASSED** |

**Notion case 全 Done**：CM-873/874/876（前棒）+ CM-886~893（本日）。基線報告存 `docs/security-reports/2026-07-25/`（早上收官 6 檔 + 下午 `-final` 6 檔，同日兩輪並存）。

**本日 BE commits（時序）**：`ecffff39`(CM-888 GitLab 附件真 bug) `9de55a8e`(semgrep ERROR 消音) `1ac436a5`(hotspots 審查) `d245cb72`(Quality Gate) `e52ea26b`(weasyprint 69.0) `f972d92d`(semgrep WARNING 消音) `e81c8c05`(CM-892 img src 限縮) `456f1a1d`(CM-893 拔 Google Fonts+字型修正) `747bd35c`(主機依賴文件) `6579e2b8`(runner 自寫交接) `62a0c465`(尾巴收零小修)
**FE commits**：`7b2cd96`(CM-887 BaseService) `c8aa7bc`/`480090d`/`c634f32`/`9c59c8b`(CM-886 a11y×4) `a6a895b`(semgrep 消音) `40e8d4c`(runner 樣式) `5785c58`(S6638)

**重要事實**：
- weasyprint「no-fix」是 GHSA patched 欄位缺漏誤導，69.0 實際已修（論證文件 `2026-07-25-weasyprint-cve-2026-49452-resolution.md`）
- SonarQube 26.7 MQR 模式下 hotspots 規則已併入一般 issues，hotspots 恆 0（`2026-07-25-hotspots-review.md`）
- CM-888 挖出真 bug：GitLab 附件刪除原為「全刪」，已改檔名定位
- CM-893 挖出字型陷阱：`Noto Sans TC` 在部署主機不存在，會 fallback 日文字型——已改 `Noto Sans CJK TC`（主機層依賴見 `docs/claude/host-dependencies.md`）
- **未 push**：BE/FE 本日全部 commits 未推，push 等 user 明示
- **部署對齊未做**（user/運維側）：部署機 `poetry update`（weasyprint 69.0 + 先前 jedi 升版）、classify image rebuild、字型 `fonts-noto-cjk` 確認——見前棒 handoff §3.3 + host-dependencies.md

## §2 新 arc 已完成的地基

1. **Accept 批次標記完畢（395 條，零失敗）**：三級 S3776×236 + S3516×8、二級緩做組 S1172×80 + S107×37 + S7721×34。全附裁決 comment。效果：**open CODE_SMELL BE 776→450、FE 664→595**
2. **清理 case 群已開（Notion，Not started）**——case no 以 Notion 實查為準（開案順序①~⑤）：
   - **① FE S6853 label 殘量 ~120**：手法同 CM-886（已 Done 可參照），runner 接
   - **② 註解碼 BE S125 ×66 + FE ×65**：純死碼刪 / 含意圖改寫說明 / FR-038 stub 註解不動，runner 接
   - **③ BE logging 桶 S3457 ×34 + S8572 ×30 + S1192 殘量 ~40**：等價改寫，runner 接
   - **④ FE 語法/樣式桶 ~200**：CSS 對比度 ×48（**先對 guidant-design-system，勿自創色**）+ 棄用語法 + 一行級改寫，runner 接
   - **⑤ BE 語意桶 73 條（S8786 regex ReDoS / S5754 裸 except / S5886 回傳型別）**：**需逐條查證，主 session 派 subagent 做**，非 runner 機械活
3. 另注意：runner 曾自行開 **CM-894**（見 BE commit `6579e2b8` 訊息「CM-894 開案待動工」）——接手時 Notion 查一下該條內容避免與 case 群重工

## §3 下一棒的工作

1. **跑 §6 pre-flight** 確認狀態
2. **派工順序建議**：⑤ 語意桶派 subagent（S8786 優先，有真實 ReDoS 面）；①~④ 等 user 的外部 runner 自取（主 session 不要 spawn subagent 做這四條——見冷接自檢③）
3. **runner 產出的驗收**：user 驗過標 Done；主 session 可 diff 抽查品質（本棒抽查零返工，維持此標準)
4. 全部清完後：重掃一輪看殘量長尾，殘量要嘛再收一輪要嘛 accept，由 user 裁決
5. **不在 scope**：CI/CD 實作（user 明示等環境）、S3776/S3516 重構、已 accept 的 154 條

## §4 帳面數字速查（清理 arc 起點）

| | BE | FE |
|---|-----|-----|
| open CODE_SMELL（accept 後） | 450 | 595 |
| 其中 case 群涵蓋 | ~140（②③⑤） | ~320（①②④） |
| 清完預估殘量 | <100 | <250 |

## §5 該讀的檔案

- `docs/features/security-scan-2607/sonar-quality-gate-setup.md` — gate 條件/CI 接法/projectVersion 注意
- `docs/features/security-scan-2607/2026-07-25-hotspots-review.md` — hotspots 0 條的原因
- `docs/features/security-scan-2607/2026-07-25-weasyprint-cve-2026-49452-resolution.md` — not-affected 論證
- `docs/claude/host-dependencies.md` — 部署主機字型/LibreOffice 前提
- `docs/claude/notion-bug-loop-runner.md` — runner 紅線
- memory：`feedback_runner_means_external_loop_runner`、`reference_security_scan_tooling`

## §6 Pre-flight（接手必跑）

```bash
cd ~/Projects/Billows/Audit-Manager/compliance-manager-be
git log --oneline -3   # 應見 62a0c465 / 6579e2b8 / 747bd35c（之後 runner 可能再疊 commits，屬正常）
git status -sb          # main；untracked 僅既有已知項
cd ~/Projects/Billows/Audit-Manager/compliance-manager-fe
git log --oneline -2   # 應見 5785c58 / 40e8d4c（runner 可能再疊）
# Sonar 帳面（token 用 grep 抽，勿 source zshrc；API 回應落檔再 jq，勿 echo 管線）
TOKEN=$(grep -E '^export SONAR_USER_TOKEN=' ~/.zshrc | sed 's/.*=//; s/"//g')
curl -su "$TOKEN:" 'http://192.168.50.171:9000/api/qualitygates/project_status?projectKey=guidant-ai-backend' -o /tmp/qg-be.json && jq -r .projectStatus.status /tmp/qg-be.json   # OK
curl -su "$TOKEN:" 'http://192.168.50.171:9000/api/qualitygates/project_status?projectKey=guidant-ai-fe' -o /tmp/qg-fe.json && jq -r .projectStatus.status /tmp/qg-fe.json   # OK
# BE 服務（若需）：目前 pid 48289 在 8000；重啟標準式：
# lsof -ti :8000 | xargs -r kill -9; nohup poetry run python -c "from dotenv import load_dotenv; load_dotenv('.env'); import runpy; runpy.run_path('main_app.py', run_name='__main__')" > /dev/null 2>&1 &
# curl -s -X POST localhost:8000/api/1.0/login -H 'Content-Type: application/json' -d '{}'  # 400=正常
```

## §7 行為規範重要提醒

- 不切 branch / 顯式 git add 禁 -am / **push 永遠等 user 明示**（本日兩 repo 全部未推）
- 「派 runner」= 只開 Notion case；主 session 派工 = spawn subagent。兩者不可混
- Sonar 標記類操作（accept/falsepositive）走 server API，附 comment 註明裁決出處
- 掃描輸出進 `docs/security-reports/YYYY-MM-DD/`（正式存證）或 /private/tmp（過程驗證），禁根目錄
- 大檔一律 jq；Sonar API curl 落檔再 jq
- BE 改 service 後重啟（kill -9 + load_dotenv 標準式）；user 說「先不用/等等」就停手

## §8 給 fresh session 的超短 prompt

```
請讀 docs/features/security-scan-2607/handoff/2026-07-25-security-arc-close-and-smell-cleanup-handoff.md，
先答 §0 冷接自檢 4 問（不跳過 WHY），再跑 §6 pre-flight。
資安 arc 已全案終結；你的工作是 Sonar 存量清理 arc：
⑤ BE 語意桶（S8786/S5754/S5886）派 subagent 做，①~④ 是外部 runner 的 case 不要碰。
push 永遠等我明示。
```
