# FR-154 feature/FR-139 合回 main 收尾 — LOG（append-only，每棒一 block）

## 2026-10-21 首腦第 1 棒（原為 FR-151 首腦第 6 棒，本 FR 自其 STATE §5.0 拆出）

- 決策者宣告準備合回 main。首腦唯讀盤點整條 `feature/FR-139`（merge-base `24cc72972`，BE 694 commits）寫成總清單；先做 1～3（套件發版 jedi `56a2f0de`＋`bdd5b90c`、還原 pin BE `7bc35752c`、基線重產 BE `8f7cc9bc5`）。乾淨庫重演抓到三個坑並修：04 產生器漏 `is_menu`、FR-144 與 FR-148 seed 斷言寫死中間態。
- 教訓：重產基線的「驗」不能只看 diff 與 stamp gate，乾淨庫 init＋migrate 實跑才抓得到「出貨 seed 已是最終態」的順序坑。
- 教訓：總驗收 STATE 停在 10-17 只管 FR-139～147，之後的 FR 沒人彙總收尾——長 branch 收口要以 git（merge-base、manifest、lock、套件 version-bump commit）重新盤點，不能拼各 FR 的 STATE。
- FR-149.3 派出並驗收（CM-2903 → BE `b6e835785`）。派前先確認「需求仍成立」（範本三段亞航字仍在、母卡無改判），不只確認「沒人做」。
- 四題全裁（照首腦建議）：風險 Excel 三欄且可匯入、風險等級只改名；FK 索引這版補；FR-147 空格語意不統一只寫明；#69 併進版、#71 下版。
- 開十張子卡 CM-2965～2974，起初散掛六張 FR 母卡並自創需求編號 `MERGE-2610`；決策者兩度點出（「不是要開母卡？」「為什麼不當一個新 FR？」）→ 補母卡 CM-2975，再升格為 FR-154，需求編號改 `FR-154` 與 `FR-154.1～.10`，STATE 自 FR-151 STATE §5.0 搬出。
- 教訓：**「不是功能」不是不編 FR 的理由**——FR 編號管的是「會跨 session 的工作 arc」，自評（FR-138）、官網（FR-152）都編了；先例 `acceptance-2610-fr139-147` 用非 FR 命名，結果就是沒人接、不在登記表。
- 教訓：工作坊是「選母卡派」，一批要一起派的卡就要同一張母卡。
- 教訓：用 agent-workshop 的 `notion_create_case.py` 會建到工作坊自己的任務庫；先建錯十張已 archive，改用其 spec 格式配 BE `notion_case.py` 的 `DATASOURCE_ID` 重建。
- 教訓：開十張跨六個 FR 的卡探脈佔大半時間，決策者問「開這麼久」；下次先回報「要查 N 處、預估多久」或分批出。

## 2026-10-21 首腦第 2 棒（工作坊 session「CM-2975-首腦」：Stage 1 驗收）

- 決策者在工作坊派七張（CM-2965～2971 扣 2972、加 2973），全部一輪通過 → `驗收通過待確認`。每張實際核對：開 commit 看檔、BE 測試自己重跑（2965 三支 159 綠；2967 守衛 2 紅 1 紅與小弟一致）、DEV／STG／POC／188 基線唯讀查索引（2966 只 DEV 有）、整站 `mkdocs build --strict` exit 0／0 warning、SPEC 頁 grep 沿革句型與 `border-left` 皆 0、手冊「我的稽核任務」0 筆。
- CM-2967 守衛紅燈逐條開 FE 檔判定：2 處真落差（MfControlsToolbar 批次設定負責部門掛 resource-library.update 但後端守 raci.manage；JobExecutionDrawer 外層 read 蓋子元件寫鈕）、4 處沒洞但違規範（三顆寫入鈕無 v-can、TaskDueDateRow 散寫 hasCap）、1 處掃描器盲區（risks/import/${mode} 動態路徑）。守衛紅著不合 main → 開 CM-2976（FR-154.11，Stage 1，sonnet／medium）。
- CM-2971 小弟指出「兩端空格語意不同」前提已被 4d `bfda2fe8a` 收掉（兩端皆空白＝不變動）；首腦開該 commit 與 `ao_task_guidance_service.py:189` 確認屬實。決策者 §2.3 裁定無事可裁；FR-147-STATE 第 50、58 行劃掉並寫明。
- 教訓：**派工卡引用 STATE「待裁」段前要對 git log 驗前提**——FR-147-STATE 10-17 之後沒更新，4d commit message 明寫「順帶收掉 4a／4b 不一致」卻沒人回頭劃；首腦開卡時照抄，決策者多裁了一題。
- 教訓：同批文件卡用 `git commit -- <檔>` 整檔提交 `mkdocs.yml`，先 commit 的會夾帶後 commit 的 nav 行（CM-2970 帶進 CM-2969 三行），build 短暫紅到對方頁落地。內容無損，但下次同批改同一 yml 的卡要在 prompt 註明「build 因別人 nav 紅不算你的」（本棒已這樣寫，小弟照報）。
- 教訓：五張 SPEC 卡對 `site/` 建置產物處置不一（四張不 commit、一張只 commit 自己頁），工作樹留 190 檔。卡上該明寫 `site/` 歸收尾棒統一 build，不要各自決定。
- 教訓：zsh 迴圈 `for p in "a b"; do set -- $p` 不會拆字（`$2` 空），用明確配對或 `read -r a b <<< "$p"`。
- 本棒工具：建卡用 BE `scripts/notion_create_case.py`（建到 CM 庫）＋ PATCH `/pages/<id>` 補四欄（母卡 relation／Stage number／Model select／Effort select）；腳本本身仍不支援四欄，STATE §5 的待補項未動。
- （同棒續）CM-2972 通過（`8afcd67f5`）；整站 strict build 0 warning，Stage 1 六張 SPEC 卡全部落地。CM-2976 第 1 輪退回：小弟把外層 v-can 搬到 `<template>` 讓守衛綠，但 Vue 只在 `<template>` 當下帶 v-if／v-for／v-slot 時才視為結構節點，v-can 到 transform 階段才改 v-if、已成一般元素，編譯出真 `<template>` 標籤被瀏覽器藏起來——首腦用 `@vue/compiler-dom`＋`vCanTransform` 編譯再 SSR 渲染證實（輸出 `<div><template><span>…`）。守衛只掃字串不渲染所以綠。
- 教訓：**v-can 守衛綠 ≠ 畫面對**；凡改動 v-can 掛點位置（不只是加減），驗收要編譯該 template 看輸出，不能只跑 vitest／三向守衛。`<template v-can>` 是陷阱，全 FE 原本 0 處使用，退回後應回到 0 並在 `vCanTransform.js` 檔頭補一行陷阱註解。
- 教訓：派工卡寫「②先查守衛怎麼收功能點再動」是對的方向，但沒把「`fe_vcan_scan.py` 第 9 行：掛在子元件標籤＝整支子元件 API 算這顆」這條規則直接貼進卡，小弟自己找到規則卻選了錯的繞法。規則本身能貼就貼，少一次猜。
- （同棒續）CM-2976 第 2 輪通過（FE `0eb060f5`、BE `223bd7738`）：A 方案，read 守門掛子元件根 div；首腦用 `@vue/compiler-sfc` 編譯三 SFC 確認 `createElementBlock("template"` 為 0、`$can` 14／6／5；守衛 FE 6/6、BE 12/12。**Stage 1 十張全數驗收通過待確認**，CM-2974 arc-review 可派。
- 教訓：小弟第 1 輪回寫老實寫了「沒實際渲染驗證」，首腦正是循那句去編譯才抓到。**打折處是驗收的路標，不是免責聲明**——驗收先讀打折處再決定補什麼驗。

## 2026-10-22 首腦第 3 棒（排程 04:03 自動觸發：CM-2974 arc-review 驗收）

- 決策者 10-21 晚交代「兩點派、四點驗」，首腦以 CronCreate 一次性排程 04:03 自驗。小弟 02:34 落報告（`afa7f52de`，372 行），九支 agent（opus 7／sonnet 2）全帶 model。
- 八條阻斷級逐條開檔到行：B1 `_template_readable` 對綁專案範本只驗讀權；B2 `_require_participant` docstring 自承不升 manager、DELETE 只擋 legacy；B3 `rk.description = desc or rem` 讓 `has_risk` 成立；B4 `AllPoamClosedCheck.check` 一律 ok、FE 五處 Banner 只兩處帶 intercept；B5 `store_issued → plan → _app.build:101` 與預覽同一支吞錯 builder；B6 三語 0 筆；B7 2,595→2,632；B8 801→808 且 CLAUDE.md 例外清單無 DI 檔。**八條全真、無誤報** → 通過。
- **重要級 1 推翻首腦昨天的判斷**：CM-2976 ① 我把「批次設定負責部門」鈕改掛 `GRC_RACI_MANAGE`，依據是守衛訊息「打的 API 後端守 raci.manage」；實際那顆鈕打 `control-org-units/batch`（守 `oscal.ssp.update`），守衛把同檔另一支 RACI 呼叫算進來了。昨天給決策者的 (a)「管理員勾 raci.manage 給顧問」作廢。
- 教訓：**守衛訊息列的「打的寫入 API」是該檔所有呼叫的聯集，不是那顆鈕的**；判一顆鈕該掛什麼，要開 dialog 檔找它實際 `put/post` 的路徑，再對後端 route 的 `require_capability`。昨天少開一個檔就下了結論。
- 教訓：排程驗收可行——卡狀態＋報告檔存在＋commit 三重判定「做完了」才驗，避免驗半成品；Notion 連續 append 會 429，重送前先 `get` 確認卡尾沒落半截。
- 待決策者：圈阻斷級修正範圖（STATE §3.1 給了 A～D 四張卡的切法與 model）、裁 B8 規範、裁重要 19／20 與 ISO PDF 授權。
- （同棒續，決策者醒後裁定）阻斷 8 條全修、重要級修 12 條、其餘下版；B1 採「不帶處理人」；B8 豁免 DI 檔；FR-150 D7 改合併知情只改文件；ISO PDF 改官網連結（英文）。首腦查 ISO 官網與版權頁：27001／27002 無免費官方全文或介紹 PDF，版權條款明寫不得放內網／共享平台，「找官方 PDF 放上去」不可行 → 改 reference_url＋說明卡＋自行上傳。
- 開七張修正卡 CM-3002～3008（FR-154.12～.18），四欄已補，spec `notion-cards-review-fixes.json`。建卡後再 PATCH 四欄，Notion 連續 PATCH 要 sleep 並接 429。
- 教訓：決策者問「連結語言是什麼」——我寫「ISO 連結語言」時沒想到他看不出這是「英文頁 vs 法文頁」這種不必問的小事。不必決策者選的事不要列成選項；列了就要一句講明是什麼。
- （同棒續）七張修正卡全部一輪通過。驗法：九個 commit 逐檔開 diff；BE 守衛全套＋七張新測試 667 過 4 紅——**4 紅用唯讀 worktree 在 `fd84e5943` 重跑證實動手前就紅**（平行 session 殘留），寫進 STATE §3.2 要另收；FE v-can-guards 6/6、`vite build` exit 0、ProjectPlanningView 2,632→2,591；docx 用 zipfile 重數客戶字串 0；DEV 實查 019 新版已套（file_uid 空、reference_url 填、upload_files 刪）、稽核員 export 權已補。
- 發現：CM-3002 卡上我寫「DELETE 只放行 legacy」是寫反（legacy 本來就唯讀），小弟兩邊都擋沒放寬、還老實問了——卡寫錯時小弟照現況判斷並回問，是對的行為。
- 🔴 待決策者：**jedi-oscal-v2 2.7.1 發版推 Nexus**（pin 已指 2.7.1，不發版 build 機會壞）；守衛 4 紅另開卡；基線重產；重要 3 寫入端裁示。
- 教訓：Notion 連續 get／append 七張會 429，要每張間隔 ≥6 秒並接 retry_after；驗收多張時先把 commit diff 全看完再抓回寫，不要一開始就打七次 API。
- 教訓：zsh `for p in "a b"; do set -- $p` 已踩第二次，改用 `${p%%:*}`／`${p##*:}` 拆字串。
- （同棒續，決策者裁三件後執行）①jedi-oscal-v2 2.7.1 推 Nexus：build 後先 `unzip -l` 確認 wheel 內無 ISO PDF（只剩 CMMC×2＋CRA）才 publish；poetry 這版 publish 不收檔名，把 dist 舊版 mv 到 dist-old 再推；BE `poetry update` 切回 Nexus 來源 `00d90a396`，realpath 指 site-packages 無 symlink。②基線重產：先 dry-run gen_schema 確認 02 與基線庫同步（只 \restrict 雜訊）→ 容器內 pg_dump 備份 → 基線庫套 CM-2966 → **發現 CM-3006 手改 04 會被 gen 沖掉**（04 由 `gen_shipped_roles_sql.py` 從 `shipped-roles.json` 產），改源頭 json → 三支 gen → 02 零刪除只多兩索引、04 排序後只差日期、99 gate (a) 綠 → `834d2f811`。③重要 3：FR-147 D2 本來就寫明不要求 manager，arc-review 沒對到；補一句 `a2c5eac6c`。
- CM-3009 通過：守衛 576 綠 0 紅；路由三支登記 PENDING 不豁免、解析點八點分類正確、Redis 六前綴皆非 key、jedi 鏡像綠。帶出一題待裁：review-step-templates GET 無 read 能力點，建議改附錄 C 列 JWT_ONLY。
- 教訓：**04-seed 是 gen 產物，手改必被沖掉**——CM-3006 卡上我寫「04-seed-core.sql:710 加一行」是錯的指引，正確是改 `resources/roles/shipped-roles.json`；README 第 29 行早寫了「不要手改 04」。開卡時指定路徑前要先看該檔是不是產物（記憶 feedback_card_check_capability_index_before_prescribing_path 的同型）。
- 教訓：`rm -rf dist/*` 被安全檢查擋是對的——publish 不需要刪舊檔，mv 到旁邊就好；順手刪不是必要動作就不要寫進指令。
- 教訓：arc-review 的「重要級」要先對 design 決策表再列——重要 3 其實是 D2 已定案的本意，reviewer 沒對到；首腦當時也沒對，多讓決策者裁了一題。
- 決策者裁「先 push 一版、bump 之後再做、安裝包先等」並放行 push：三 repo `feature/FR-139` 推 origin（BE 18 commits `ee88d5e6d`、FE 15 `7ba85915`、jedi 7 `223cc823`），不碰 main、不 force。BE 工作樹 190 檔 `site/` 產物與 CLAUDE.md／FR-144／151 HTML 未提交改動不是本棒的，未動。發版時移開的 `dist-old` 已移回 `dist/`。
