標籤: Cycle SOP

  • 「為什麼修不完?」— 從 21 輪迴圈到 5 type taxonomy 的多 agent 角色設計

    場景

    你接手一個 multi-tenant 專案,系統有 5 個角色(sysadmin / 主委 / 警衛 / 戶長 / 住戶),不同角色有不同 RBAC 權限。你建了 AGENTS.md 派 1 RD + 1 QA,以為這就是 multi-agent team。

    然後出事了。

    本系列【入門篇】· 給「想知道為什麼」的人

    這篇談為什麼 multi-agent 工程需要 cycle file workflow + 5 種 agent type
    怎麼用8 幕劇 · 第一人稱故事 · 真實踩坑反推
    下一步讀完想看 怎麼做(8-stage SOP / 4 個檔範本 / bootstrap)→ 進階篇

    本篇路線圖

    幕 1AGENTS 兩角色跑起來 → 局部檢測 + 不會按角色測(第一次嚴重問題)
    幕 2要求按角色登入測試 → 一天 flip-flop(換角色每次都不對)
    幕 3小白角色誕生 — 不問對錯 / 按 SPEC 走 / 問 PM
    幕 4PM 回到多元職能 → 原本「開發+QA」結構無意義
    幕 5後來踩 R12 — 11 輪 self-audit 還是漏 P1
    幕 6C29 派 5 個 persona — Newbie 多元化
    幕 7從踩坑反推 5 個 type 的形狀
    幕 8每個 cycle 派幾個 — dynamic staffing

    幕 1

    AGENTS 兩角色跑起來:局部檢測 + 不會按角色測

    當時我以為「2 個 agent ping pong」就是 multi-agent。AGENTS.md 配:

    RD agent(寫 code) + QA agent(跑 audit)

    跑起來幾輪後問題顯現,QA 的 audit 有兩個結構性缺陷:

    QA 在做什麼 缺陷 為什麼致命
    ① 局部檢測 只看單一 resolver / 單一 endpoint · 看不到跨檔/跨系統的互動 系統整體性沒被驗
    ② 不會按角色切換進入測試 QA 都用「一個視角」測,從來沒登入過不同 RBAC 角色看是不是被擋對 / 看到對的東西 RBAC 路徑(最重要的安全特性)完全沒檢查

    為什麼「不會按角色測」是嚴重問題

    RBAC 角色 看到什麼 / 能做什麼 沒測會怎樣
    sysadmin跨社區管理cross-tenant leak 沒驗
    主委本社區管理能看到別社區?能改別人家?
    警衛處理包裹/訪客能看到住戶資料嗎?
    戶長管自己家能看到別家的包裹?
    住戶看自己包裹能查到別人寄件?

    第一次嚴重問題:QA 表面綠燈,但 RBAC 跟多租戶隔離這兩條最重要的安全路徑完全沒被驗過——因為 QA agent 從來沒登入過不同角色。系統最該被守住的地方,變成最暴露的地方。


    幕 2

    要求按角色登入測試:一天 flip-flop

    我介入,告訴 Claude:「不要只在後端查 code,實際用各個角色帳號登入測。」

    它真的開始用 sysadmin / 主委 / 警衛 / 戶長 / 住戶 五個帳號登入測。但很快變成:

    輪次 用哪個角色測 QA 說 RD 動作
    輪 1sysadmin抓到 5 個淺問題RD 修
    輪 2主委「剛剛修的東西在主委角度看是不對的」RD 改
    輪 3警衛「警衛角度又不對」RD 又改
    輪 4戶長「戶長角度又不對」RD 又改
    輪 5住戶「住戶角度又不對」RD 又改
    輪 6回到 sysadmin「現在 sysadmin 角度又不對了」(因為剛改的把 sysadmin 弄壞)RD 又改
    5 個角色輪流每換一個角色就抓到「上輪修壞了」永遠在改

    這樣無限循環了一天

    每輪都是「淺淺檢測 5 個問題 → RD 修 → 換角色又不對」

    最後我叫停。

    失敗 insight:QA 每次按角色測都對(以那個角色的視角看),但加起來都不對(角色之間有衝突)。沒有公共的「對」基準——每個角色都是 QA 自己定義的「對」,沒有 SPEC 在中間定錨。


    幕 3

    小白角色誕生:不問對錯 / 按 SPEC 走 / 問 PM

    叫停之後我重新設計。問題不在「QA 不努力」,在「QA 一邊測一邊自己定義對錯」——這個 mode 永遠 flip-flop。

    新角色:小白。他長這樣:

    小白特性 具體動作 解掉什麼
    ① 不問對錯 只報「我看到什麼」,不下「這對 / 這不對」的判決 QA 自己定義「對」→ flip-flop
    ② 按 SPEC 走 拿 spec 文件去測,測 spec 寫了什麼。Spec 沒寫的就算了 QA 一邊測一邊提新需求 → 規格膨脹
    ③ 有問題問 PM 看到不對勁但不確定 → 報 OPEN finding,送 PM 判 QA 直接 ping RD 修 → 沒人擋
    小白 audit → 報 finding(不下對錯) → PM 對 SPEC 比對 → 是 bug 才給 RD 修

    小白的本質不是「換一種 audit 風格」,是把「判對錯」這件事從 audit 角色拿走,送回 PM 那裡。Audit 只負責觀察,PM 才負責對 SPEC double-check。


    幕 4

    PM 回到多元職能 → 原本的 AGENT 結構無意義

    小白把「判對錯」送回給 PM 之後,PM 不能只當「triage 一個動作」。PM 的職能本來就多元,只是 R35 兩角色設定下我把這層拿掉了。現在它回來了:

    PM 職能 具體動作 為什麼需要
    ① 對 SPEC double-check 每個 finding 拿 SPEC 比對:是不是 bug?還是小白看錯? 提供公共「對」基準
    ② Finding 4 選 1 分判 bug(該修) · feature(進 backlog) · usage(改 docs) · not_issue(close) 不讓所有 finding 都進 fix loop
    ③ 規格定錨 小白報「這應該也要 work」→ PM 判斷該不該加進 SPEC,加的話寫 INV-XXX-NNN 擋 spec 漂移
    ④ 跨角色視角整合 這個 finding 在 sysadmin 角度跟主委角度有衝突 → PM 拿 SPEC 判哪個角色該贏 解掉幕 2 的「換角色 flip-flop」

    原本的 AGENTS.md 結構變無意義

    最早 AGENTS.md(失敗) 小白 + PM 出現後
    RD agent RD 還在,但只接 PM triage 過的 bug
    QA agent(直接 ping RD) 變小白(不問對錯 / 按 SPEC / 報 PM)
    (沒有 PM) PM 多元職能進場
    結構:RD + QA ping pong 結構:小白 → PM → RD 三角入口

    學到的事 → Multi-agent 不是「派幾個 agent」的問題,是「agent 之間誰擋誰、誰判對錯」的問題。沒有公共 SPEC + PM 守門,任何 audit 方式都會撞 flip-flop。


    幕 5

    後來踩 R12:11 輪 self-audit 還是漏 P1

    小白 + PM 結構穩定後 cycle 順暢很多。我以為角色設計問題解了。然後 R12 cycle 出事。

    R12 cycle 條件 數字 / 結果
    我自己跑 audit11 輪
    場景文件覆蓋132 個
    所有人簽 ✅RD ✅ · PM ✅ · 我 ✅ → merge
    事後發現P1 漏掉:戶長能看到整個社區的資料

    為什麼 11 輪 + 132 場景還漏?

    11 輪 self-audit 11 個獨立檢查
    同一個視角(我自己)跑 11 次11 個不同視角各跑一次
    寫的時候的盲點,驗的時候也是盲點不同視角會覆蓋不同盲點
    132 場景由同一視角設計不同視角會想到不同場景
    等號不成立

    解法:把小白進化成「fresh newbie」(零 context)

    Newbie 條件全新 sonnet,沒給過去 11 輪的 audit context · 不知道之前抓過什麼
    紀律沿用小白規矩(不問對錯 / 按 SPEC / 問 PM),只是「context 比小白更乾淨」
    結果第一輪就抓到那個 P1

    學到的事 → 小白本身不夠,要再進化成「零 context」的 fresh newbie——避免「跑著跑著也累積成跟原 audit 同視角」的退化。


    幕 6

    C29:派 5 個 persona 平行 audit

    一個 fresh newbie 補一個盲點。不同 newbie 帶不同假設 → 平行補多個盲點。所有 finding 仍走 PM triage,不直接給 RD。

    # Persona 他的世界假設 抓到的盲點
    高吞吐警衛阿伯 每天 300 件包裹,每秒都要省 FAB 排太多 · 批次掃描藏在三點選單
    無棟透天主委 12 戶共一棟,沒有「A 棟 B 棟」 後端硬擋空「棟」欄位
    多棟社區主委 5 棟,選戶必須先選棟 picker dropdown collision
    老年用 iPhone 11 375px 螢幕、視力差 FAB 不在拇指區、按鈕找不到
    跨租戶 RLS 測試者 拿 A 社區帳號戳 B 社區資料 RLS policy 守不守得住

    5 個 persona 抓出 23 個 finding

    4 個 cycle blocker · 全部都是 PM + 我自己漏掉的

    小白 → newbie → persona newbie 的進化線

    設計 解掉什麼
    第一代
    小白
    不問對錯 / 按 SPEC / 問 PM QA 自己定義對 → 換角色 flip-flop
    第二代
    Fresh Newbie
    零 context · 不知道過去 audit 結果 小白跑久了累積成跟原 audit 同視角 → shared assumption
    第三代
    Persona Newbie
    多 persona 平行 · 各自帶不同世界假設 單一視角必有盲點 → 多視角覆蓋

    幕 7

    從踩坑反推:5 個 type 的形狀

    走過這幾個踩坑,5 個 agent type 不是想像出來的,是反向工程的結果:

    Type 動作 並行? 從什麼反推
    Writer 寫 code / spec / migration NO(單線程) 原本 RD 角色 · 兩 writer 平行會打架
    Verifier scope 鎖死 1-3 INV 的 audit · 按 SPEC 走 YES 第一代小白 · 解「QA 自己定義對」
    Triage 對 SPEC double-check · 4 選 1 分判 · 規格定錨 · 跨角色整合 NO(人類) PM 多元職能 · 解「換角色 flip-flop」
    Comparison 零 context 的獨立 verifier · 不知道原 audit findings YES 第二代 fresh newbie · R12 11 輪漏 P1 · shared assumption
    Newbie Adversarial persona-driven audit YES 第三代 persona newbie · C29 23 finding · 單一視角盲點
    傳統 8 職稱 這 5 個 type
    架構師 / PM / UI-UX / 後端 / Flutter / DBA / QA Writer / Verifier / Triage / Comparison / Newbie
    組織圖長相 · 看起來工整 動作類型(寫不寫 / 並行不並行 / 判不判對錯)
    寫進 AGENTS.md 之後 cycle 跑起來,只有 PM/QA 對應到事故學到的 每個 type 對應一條真實踩坑

    幕 8

    每個 cycle 派幾個?

    5 個 type 有了。但每個 cycle 派多少?不同 cycle 規模需要不同編制:

    Cycle 規模 派誰 總 RAM 為什麼
    改 1 行 typo RD-Sonnet + Verifier-Haiku ~1.0 GB 簡單變動 · 簡單覆蓋
    中等 PR RD-Sonnet + 2 Verifier-Haiku + Comparison-Haiku ~2.2 GB 中等變動 · 需 cross-check shared assumption
    大改 schema(含 RBAC) RD-Opus + 3 Verifier-Sonnet + Comparison-Haiku + 5 Persona-Newbie ~5.5 GB 大變動 + 跨角色 · 需多視角補 RBAC 盲點
    固定編制(每 cycle 都派同樣 N 個) Per-cycle dynamic staffing
    小 cycle 浪費資源小 cycle 派 2 個 agent
    大 cycle 漏 perspective大 cycle 派 9 個 agent
    9 Opus 撐爆 16 GB 機器每 cycle 算一次 budget

    規劃 vs 執行 staffing 分離

    AGENTS.md不變部分(taxonomy + RAM 上限 + Iron Rules) · 半年不變
    docs/cycles/Cn-*.md Header具體 staffing(派誰 / 什麼 model / 多少 RAM) · 每 cycle 重算
    前者性質規劃文件
    後者性質執行契約

    結語:cycle file 是這故事的結晶

    維度 補丁 從什麼反推
    角色 5 個 type taxonomy + PM 多元職能 + 小白進化線 局部檢測 / 不會按角色測 / 換角色 flip-flop / shared assumption / 單一視角盲點
    流程 8-stage SOP + 小白 → PM → RD 三角入口 沒收斂條件 / 沒規格定錨 / 沒 SPEC 守門員
    資源 per-cycle dynamic staffing 固定 9 Opus 撐爆機器

    cycle file workflow 的價值不是「設計得多漂亮」,是「每個設計選擇都對應到一個踩過的坑」。Multi-tenant + RBAC 系統的盲點不是「LLM 不夠強」,是「沒有公共 SPEC 守門員 + 多元視角覆蓋」就會撞牆。

    你接手新專案那天

    需要什麼4 個檔案 + 一段 bootstrap prompt
    完整版在哪進階篇

    系列文章

    第一篇「56 條 INV 全綠,user 點一次抓出 4 個 bug」— Multi-Agent 業界共識的五個自家補丁
    進階篇Cycle File:Multi-Agent 工程的狀態接力棒 — 完整 SOP / 8-stage / 4 個檔範本
    呼應業界Multi-Agent 架構再探: 三省六部反模式和業界收斂共識(愛好 AI 工程)
  • Cycle File:Multi-Agent 工程的狀態接力棒 — file-as-state-machine 方法論

    重點摘要

    • 動手的 agent 只能一個(寫入單線程)。但同一個 agent 不可能從頭做到尾,工作數小時後注意力品質下降(context rot)。
    • 解法不是換 agent,也不是加 agent,是讓「下一個 agent」能無痛接手。接力棒設計才是 multi-agent 工程的真正關鍵。
    • Cycle file = file-as-state-machine:把每個 cycle 的完整狀態寫進一份 markdown,活在 git,跨 session 可讀,撐過對話 compaction。
    • 8-stage 結構每個 stage 對應一個 multi-agent 容易踩到的坑:baseline 污染、ripple effect、vacuous test、groupthink。
    • 5 種 cycle type,各有 stage profile。不是每個 cycle 都跑 8-stage,硬塞會浪費或漏。
    • file-as-state-machine 不只 multi-agent 用得到。ADR、RFC、postmortem 都是這個 pattern,multi-agent workflow 把它的價值放大 100×。
    • 新環境 bootstrap:4 個檔案 + 一段 prompt,就能在新電腦 / 新 Claude Code / Antigravity / Codex / Cursor / Aider 上啟動這套流程,不分工具。

    本系列【進階篇】。提供完整 SOP 跟 4 個檔範本,假設你已經知道為什麼 multi-agent 工程需要 cycle file workflow。還沒看過為什麼?先讀 入門篇:「為什麼修不完?」— 從 21 輪迴圈到 5 type taxonomy 的多 agent 角色設計——用第一人稱故事告訴你 5 個 agent type 是怎麼從踩坑反推出來的,讀完再回來看這篇就會懂為什麼這 4 個檔長這樣。

    Multi-agent 工作流有個業界共識的硬約束:同時間只能有一個 agent 動手寫(寫 code / 寫 spec / 寫 migration)。多個 agent 平行寫產生隱性風格 + 決策衝突,Cognition / Anthropic / Stanford 都從不同角度驗證過這條。

    但這條約束衍生一個立刻撞上的問題:

    寫入單線程沒錯,但一個 agent 怎麼跑一個多月的長期專案不撞 context rot?同一個 agent 從第一週寫到第六週,中間累積的對話歷史不會把它壓垮嗎?

    答:不是「一個 agent 跑到底」,是「每個 cycle 換新 agent,cycle file 接力」

    這篇講 cycle file 設計方法論——為什麼必須是檔案不是對話、為什麼必須在 git 不能在 Notion、8-stage 結構每個 stage 對應哪個 multi-agent 踩坑,以及這個 pattern 怎麼推廣到 ADR / RFC / postmortem 這類非 multi-agent 場景。

    對照組:傳統工業界 RD 開發流程

    在進入 multi-agent cycle file 方法論之前,先把工業界標準的 RD 開發流程攤開——對照基準清楚了,後面的對應關係才好讀。本文不是發明新流程,是把這套經典 SDLC 對應到能跑在多個 AI agent 上的 cycle file 結構。

    經典流程九步

    1. PM 整理需求 — business requirement,decide what to build
    2. SA 分析需求(可由 PM 兼任)— 系統分析,what the system must do
    3. SD 設計需求(可由 PM 兼任)— 系統設計,how the system should do it
    4. RD 撰寫程式 — implementation
    5. RD 自測後交付 — pre-PR self-test
    6. QA 進行測試,建立錯誤表 — finding list,QA 只報事實不下 P0/P1
    7. PM 確認錯誤表,跟 SPEC 比對 — triage:是 bug 還是 feature 還是 usage 還是 not_issue
    8. 交給 RD 修正 → 修正後再給 QA → PM,持續 loop — 直到 PM 點頭。這個 loop 是品質的核心,不是 bug,是設計
    9. 上到 GA 區,以正式資料進行測試 — production smoke,真實數據才能發現假性綠燈

    測試分三段——這三段不能混

    類型 內容 在 cycle file 對應
    測試程式 unit test / integration test / E2E test scripts Stage 5a failing test + Stage 5c regression suite
    測試環境 staging server / sandbox / test docker compose / backend services Stage 0.5 Pre-cycle hygiene 確認所有服務 up
    測試資料 fixture / seed data / disposable test users / canonical baseline Stage 0.5 fixture reset + disposable qa_* fixtures

    經典流程 ↔ Cycle file 對應

    傳統 RD 流程 Cycle file 對應 stage
    PM 整理需求 Cycle file Header 的 spec section + related INV
    SA / SD 分析設計 Spec.md + invariants.md 條目(契約寫死)
    RD 撰寫 + 自測 Stage 1 RD 自測(單線程,一個 agent 動手)
    QA 測試 + 錯誤表 Stage 2 QA wave 並行 + Stage 3 OPEN findings
    PM 確認比對 SPEC Stage 4 PM triage(bug / feature / usage / not_issue)
    RD 修正 → QA → PM loop Stage 5 fix → Stage 6 regression → Stage 7 comparison QA → 回 Stage 3
    PM 點頭 Stage 8 merge gate(全綠才合)
    上 GA 區正式資料測試 Production smoke + user smoke(primary detection,觸發 T-user-smoke-followup cycle)

    關鍵差別:傳統流程角色是「人」(PM / SA / SD / RD / QA),cycle file workflow 把這些角色變成「agent 在不同 stage 的職責」——同一個 LLM agent 在 Stage 1 是 RD,在 Stage 2 wave 之中扮演 QA(但 scope 鎖死),Stage 7 是 comparison QA。PM 永遠是人,因為「跟 SPEC 比對 + 做價值判斷」這層 LLM 不該越界。

    §1 為什麼「對話 context」是錯誤的狀態載體

    多數人用 Claude / GPT / Cursor / Aider 寫 code 的時候,默認狀態活在對話裡——上一句問題、AI 上一個回應、再上一個截圖,都在 chat history 裡。看起來理所當然,直到撞到三個事實:

    1. 對話會壓縮(compaction)。主流工具在 context 接近上限時都會自動壓縮歷史。「我剛剛跟你說過 X」這句話,壓縮一輪後就變成「我們討論過某些事」。具體細節進了 summary,但 summary 本身會再被壓縮。資訊密度持續下降。
    2. 對話只活在單一 session。開新 session = 全新對話,讀不到上次的 context。即使有 memory file(persistent profile / preferences),那是「人格 / 偏好」層,不是「這個專案這個 PR 跑到哪了」的狀態。
    3. 對話沒 git history。半年後翻回去看「為什麼這個 PR merge」,翻 chat log 是不可能任務——對話沒 commit message、沒 tag、沒 diff,review 工具完全用不上。

    傳統 workaround 是「我把上下文 paste 進新 session」。這是 fragile 的——你會漏、你會省略、你會把 600 字濃縮成 30 字然後新 session 推不出原本的決策邏輯。

    結論:對話狀態必然會掉,任何長期 multi-agent workflow 都要把 state 寫到對話以外的地方。Cycle file 是其中一種具體實踐。

    §2 Cycle File 的核心思想:file-as-state-machine

    一個 cycle file = 一個 PR cycle 的完整狀態機。離散的 stage 有明確 entry / exit 條件,跨 session 接手 = 讀檔不是讀對話。

    為什麼必須是 markdown 不是 JSON / DB

    • Human-AI 雙方都能讀。人要看,AI 要讀,PR reviewer 也要看。Markdown 是最低共通格式。
    • Diff 友善。Stage 3 加一個 finding,git diff 看得清清楚楚。JSON 一改整個檔重排,DB 改一個 row 沒 diff。
    • 離 code 近docs/cycles/Cn-*.md 跟 source code 在同一個 repo,branch 切換時 cycle file 也跟著切換。

    為什麼必須在 git 不能在 Notion / Confluence

    • Audit trail。每次 cycle file update 都是一個 commit,who / when / why 一目了然。Cloud doc 改了就改了,沒人記得是誰改的。
    • 跟 code 同生死。Branch 跟 cycle file 綁在一起,rebase / cherry-pick / revert 都會帶走 cycle file。Notion 不知道 code 在哪個 branch。
    • 跨工具不依賴。Cloud doc 服務掛了 cycle file 就讀不到。Git 不會掛——而且即使原 repo 沒了,每個 clone 都有完整歷史。

    §3 8-stage 結構——每個 stage 對應一個 multi-agent 踩坑

    本節拆 cycle file 8-stage 的標準結構,標出每個 stage 對應哪個 multi-agent 容易撞的坑。

    Header — cycle 身分證

    # Cycle Cn — <short PR title>
    
    Owner: <engineer agent / human>
    Started: YYYY-MM-DD HH:MM
    Status: open / in_qa / in_triage / in_fix / regression / closed
    Cycle Type: T-PR-cycle / T-regression-fix / T-feature-cycle /
                T-spec-audit / T-user-smoke-followup / T-mutation-test
    Related:
      - PR / branch: <commit_sha>
      - Spec section: <§X.Y>
      - Primary INV(s) targeted: INV-XXX-NNN

    下個 agent 接手第一件事是讀 Header。Cycle Type 決定哪些 stage 必經、哪些 N/A——不分 type 把所有 cycle 都當 PR-cycle 跑,結果 regression-fix 跑 8-stage 浪費,user-smoke-followup 跑 8-stage 又錯位(user 已經是 primary detection 了,還跑 QA wave 是反過來)。

    Stage 0.5 — Pre-cycle hygiene

    • git status --short clean(除了本 cycle 將動的 file)
    • HEAD = <commit-sha>,不是 mid-rebase / mid-merge state
    • seed / fixture reset script 跑過,fixture 為 canonical
    • 列出本 cycle 將建立的 disposable test fixtures,不複用共享 fixture
    • 所有相關服務 healthy(backend / proxy / DB / storage 皆 up)

    對應的坑:跨 cycle 副作用會讓新 cycle 在污染狀態跑出 false positive ✅。上輪 cycle 殘留的 test payload、未清的 disabled user、過期的 rate-limit lockout——新 agent 進場已經在污染狀態,QA wave 跑出來的綠燈是 false confidence。Pre-cycle baseline check 是唯一的事前防線。

    Stage 1: RD 自測

    • 單元測試全綠(附 commit SHA)
    • Live smoke:對 endpoint X / user Y 跑 happy path(寫一兩行紀錄)
    • PR header 完整(INV 宣告 / QA scope / Verification 三段)

    RD 在開 PR 之前就先過自己的關。沒過自測的 PR 連 Stage 2 都進不去——直接退回。

    Stage 2: QA wave(並行讀取)

    2-4 個 QA agent 並行,每個 scope 鎖死 1-3 個 invariant。這是 multi-agent「平行覆蓋」的核心場景——讀取不衝突。

    QA agent A — INV-XXX-NNN red-team
    QA agent B — INV-YYY-MMM regression
    QA agent C (optional) — same scope as A, no knowledge of A's findings
                           (consistency check; 結果一致則 spec 寫得清楚,
                            不一致則 spec 有歧義先收斂)

    QA agent 只能標 ✅ / ❌ / OPEN,絕對不准標 P0/P1——那是 PM 的 authority。OPEN 一律往 PM triage 走。

    Stage 3: OPEN findings(等 PM triage)

    所有 QA agent 的 OPEN finding 收進一張 finding table。Finding 格式:

    ### Finding F-Cn-001
    - QA agent: A
    - Resolver/Feature: <name>
    - Observed: <事實>
    - Repro: <exact commands>
    - PM triage:
      - Class: bug / feature / usage / not_issue / spec_clarification
      - Confidence: high / low
      - Reasoning: <≤2 sentences citing spec/INV>
      - User review needed: yes / no

    Findings ≥3 時派 PM-agent 跑 first-pass triage,user 只 review confidence=lowclass=spec_clarification 兩類。Findings ≤2 user 直接判,省 round-trip。

    Stage 4: User review(只看 low-conf)

    User 對每個 confidence=lowspec_clarification 項目走 PM triage 分判,30 秒一個 finding。超過 2 分鐘 = finding 太大,要拆。

    Downstream sweep(Stage 5 之前必填)

    本 cycle 改動的 state(DB tables / schema / role-cap definition / fixture state),列出有哪些其他 resolver / query 會讀到。grep 全 repo 找 reader,寧可 false positive 多列幾條,少列就漏 ripple。

    對應的坑:改動會 ripple 到 cycle scope 外的 readers,沒 explicit list 必漏。經典場景:Cycle A 改了 fixture seed script,衍生 1 小時後 user 點 dashboard 某個 tab 崩。原因是 Cycle A 改了某張表的 state,影響到 cycle scope 外的另一個 resolver——那個 resolver 不在 Cycle A 的測試範圍裡,沒人提醒去看,bug 就溜進去。Downstream sweep 強制 RD 在 Stage 5 開修前 explicitly list ripple 範圍,Stage 6 regression 必須 cover。

    Stage 5: RD fix(TDD red-green 拆 5a / 5b / 5c)

    Stage 5a — write failing test
      - 寫 test 對應 invariant / 對應 finding attack scenario
      - 跑 test → 預期 ❌ red(沒紅 = test 寫錯)
      - commit "test: failing test for F-Cn-NNN / INV-XXX-NNN (red)"
    
    Stage 5b — implement fix
      - 寫 fix
      - 重跑 5a 的 test → 預期 ✅ green
      - commit "fix: ... (green via test in <5a-sha>)"
      - commit message 必填 "Failing test verified at: <5a-sha>"
    
    Stage 5c — refactor + regression
      - refactor 必要時
      - 跑全套既有 test 確認無 regression

    對應的坑:「test + fix 同 commit」沒驗 test 真的會抓對應 bug,可能是 vacuous test(永遠 pass 但不 cover 要 cover 的 case)。沒有「test 先 ❌、fix 後 ✅」這個 TDD 基本動作,你不知道 test 是真的在驗還是空跑。拆三個 commit 的好處是 bisect 看得出 red→green 軌跡。

    Stage 6: Regression

    Stage 5 fix 跑完,QA agent 重跑 Stage 2 的 wave(同樣的 prompt,只是 commit SHA 換成 fix sha)。Downstream sweep 列出的 ripple 範圍必須驗。

    Stage 7: Comparison QA(對抗 groupthink)

    派一個全新的 QA agent(不告訴它原 QA 抓到什麼),跑同一份 PR。如果它抓出新 finding = 原 QA 還有盲點。如果它跟原 QA 結論一致 = 確認可信。

    對應的坑:QA agent + Engineer agent 同 LLM 譜系,想得到的 attack scenario 高度重疊,共有盲點。Comparison QA 是減輕 groupthink 的最低成本做法——成本是多派一個 agent,收穫是另一個視角的覆蓋。

    Stage 8: Merge gate

    要合 PR,全部都要打勾:

    • PR header 完整(INV 宣告 / QA scope / Verification)
    • 宣告的「滿足」invariant:兩個 QA agent 都報 ✅
    • 宣告的「可能影響」invariant:回歸都 ✅
    • 兩個 QA agent 報告結論一致
    • OPEN list 清空(全部 triage 完)
    • 單元測試綠
    • 如 PR 影響 UI → 手動 smoke 一次 happy path

    Stage 8 全綠才 merge,cycle file commit 留檔,close cycle。

    §4 Cycle Type — 5 種 stage profile,不是每個 cycle 都跑 8-stage

    「Cycle Type」field 解決一個很實在的問題:不同性質的 cycle 用不同 stage profile,硬塞 8-stage 會浪費 stage 或漏 stage。

    Cycle Type 觸發 Stage profile
    T-PR-cycle 開 PR 等 merge 完整 8-stage(QA wave + regression + comparison newbie)
    T-regression-fix Engineer / agent 自抓 regression 5-stage:skip Stage 2 QA wave + Stage 4 user review;root cause 在 cycle file 開頭講清
    T-feature-cycle Forward-going 新 feature Stage 5 在 Stage 2 之前(先實作再 QA wave 對 INV 驗證)
    T-spec-audit 隨機抽樣 / category 全驗 Stage 2 only + report;無 fix。Findings raise 為 OPEN 給 PM
    T-user-smoke-followup User 直接報 bug Stage 3 直接收 finding(user 是 primary detection)+ skip Stage 2;後續 5/6/7/8 全跑

    Cycle file 開頭強制填 Cycle Type: T-XXX,Stage 8 merge gate 只 enforce 該 type 必經的 stage。

    §5 三個工程效益——為什麼這個設計值得

    效益 1:撐過對話 compaction

    對話被壓縮的時候,壓的是 chat history,不是 git artifact。下個 session 我打開 docs/cycles/Cn-*.md,完整的 persona、attack scenario、findings、PM triage 結果都還在。

    對照組:如果這些資訊只活在對話裡,compaction 一輪 → 只剩「我們做了一些 QA」這種無資訊摘要 → 下個 agent 接手等於從零開始。

    效益 2:跨 session / 跨 agent 可讀

    新 agent invocation(無論是新 session、不同 agent、甚至不同人接手),讀檔就能上工。長期專案累積的 cycle 是獨立 Engineer invocation,每個 cycle 開頭讀 workflow SOP + invariants 契約 + 當前 cycle file 進度,3 分鐘進入狀況。

    對照組:沒 cycle file 的話,新 agent 進場第一件事是「請告訴我前面跑到哪了」——你自己要把 600 行對話濃縮 paste 給它,中間漏東漏西。

    效益 3:6 個月後的自己有 audit trail

    半年後 grep 某條 invariant ID,找到這條 invariant 是哪個 cycle 加的、為什麼加、當時 PM 怎麼判的——全部在 git 裡,commit message 帶 finding ID。

    對照組:Cloud doc 寫的 ADR、Confluence 寫的 design doc——半年後權限過期、url 換掉、search 找不到。

    §6 推廣:file-as-state-machine 不只 multi-agent 用得到

    Cycle file 的核心是 file-as-state-machine:把工程過程的 state 從「對話 / 會議 / 腦袋」搬到「檔案 / git」。這個 pattern 在傳統軟工不是新東西,只是名字不一樣。

    名稱 用途 跟 cycle file 共同性質
    ADR(Architecture Decision Record) 記錄架構決策的 context / 選項 / 決定 / 後果 活在 git,撐過人員流動,6 個月後可 audit
    RFC(Request for Comments) 大型 feature 的設計提案 + comment trail 同上;增加 review 階段的離散 stage
    Postmortem incident 事後分析 + 行動項 同上;Stage 包含 timeline / root cause / action items
    Cycle file single PR 的完整 lifecycle 同上;比 ADR/RFC 更短週期、更高頻次

    共同性質:把工程過程的 state 從可揮發載體(對話、會議、腦袋)搬到不可揮發載體(git、版控檔案)。對 single-developer 也有用——你不會記得三個月前為什麼選 PostgreSQL 而不是 MySQL,但 ADR 會記得。

    對 multi-agent 工作流,這個 pattern 的價值放大 100×。因為 multi-agent 有兩個額外的揮發源:

    • 對話 compaction(每幾小時就一次)
    • 跨 session / 跨 agent 切換(每個 cycle 一次)

    Single-developer 的對話 context 一個專案可能撐幾天,multi-agent workflow 可能撐幾小時。Cycle file 的「狀態接力棒」價值在 multi-agent 場景才完整展現。

    §7 在新環境啟動這套流程——4 個檔案 + 一段 bootstrap prompt

    如果今天換新電腦、開新專案、或換工具(Claude Code → Antigravity / Codex / Cursor / Aider),怎麼快速把這套 cycle workflow 啟動到「下一個 agent 進來就能照跑」的狀態?答案是最小可行 kit:4 個檔案 + 一段給 agent 的開場白

    最小可行 kit:4 個檔案

    檔案 內容 變動頻次
    docs/workflow.md 8-stage SOP 完整版(本文 §3 內容) 每 retro 一次 amend
    docs/cycle-template.md Cycle file 結構 template(複製即可填) 穩定,少改
    docs/invariants.md 所有 INV-XXX-NNN 契約列表(初始空白,隨 cycle 累積) 每 cycle 可能 amend
    AGENTS.md Role taxonomy(perspective-driven,不是 8 職稱)+ 資源預算上限 穩定,專案改 tech stack 時才動

    這 4 個檔不是「規劃文件」,是「執行契約」——每 PR 強制讀,違反退回。具體 staffing / per-cycle 進度寫在 docs/cycles/Cn-*.md

    4 個檔案的最小內容範本

    下面 4 段是直接可複製貼到專案的 minimal 內容。Day-1 把這 4 個檔放進 docs/ 跟 root 之後,就有完整的 cycle workflow kit,新 agent 進來照走。

    檔案 1/4 — docs/workflow.md

    8-stage SOP 的 skeleton。詳細每個 stage 規則見本文 §3,這份 skeleton 是「每個 agent 開工前必讀」的最小契約版本。

    # Workflow SOP — Cycle-based PR Pipeline
    
    > 所有 PR 走 cycle file 流程。違反 stage 順序的 PR 直接退回。
    
    ## 8 Stages
    
    | Stage | 動作 | 誰做 | 必經? |
    |---|---|---|---|
    | 0.5 | Pre-cycle hygiene (baseline 乾淨確認) | Writer | yes |
    | 1 | RD 自測 (unit test + live smoke + PR header) | Writer | yes |
    | 2 | QA wave (2-4 verifier 並行,每個 scope 鎖 1-3 INV) | Verifier(s) | yes (PR-cycle) |
    | 3 | OPEN findings table (QA agent 收 finding) | Verifier | yes |
    | 4 | PM triage (bug / feature / usage / not_issue 分判) | PM / Triage | yes |
    | Downstream sweep | grep 列出 ripple 範圍 (本 cycle scope 外的 readers) | Writer | yes |
    | 5 | RD fix — 5a 寫 failing test → 5b 寫 fix → 5c refactor | Writer | yes (有 bug 才跑) |
    | 6 | Regression (重跑 Stage 2 wave,scope 含 ripple) | Verifier | yes |
    | 7 | Comparison QA (新 agent 不知道原 QA 結果,re-audit) | Verifier | recommended |
    | 8 | Merge gate (全綠才合) | Writer + PM | yes |
    
    ## 5 Cycle Types (決定哪些 stage 必經)
    
    | Type | 觸發 | Stage profile |
    |---|---|---|
    | `T-PR-cycle` | 開 PR 等 merge | 完整 8-stage |
    | `T-regression-fix` | engineer 自抓 regression | 5-stage:skip Stage 2 + Stage 4 |
    | `T-feature-cycle` | forward-going 新 feature | Stage 5 在 Stage 2 之前 |
    | `T-spec-audit` | 隨機抽樣 / category 全驗 | Stage 2 only + report (無 fix) |
    | `T-user-smoke-followup` | user 報 bug | Stage 3 直接收 finding,skip Stage 2 |
    
    ## Iron Rules (執行契約,違反退回)
    
    1. **寫入單線程**:同時間只能 1 個 Writer agent 動手。其他 agent 都不准動 code / spec / schema / migration。
    2. **Verifier 不准標 P0/P1**:只能 ✅ / ❌ / OPEN。嚴重度是 Triage 的 authority。
    3. **Verifier scope 鎖死 1-3 INV**:不准「找任何 bug」(R35 21 輪迴圈的反面教材)。
    4. **TDD red-green 拆三 commit**:Stage 5a failing test red commit → 5b fix green commit (帶 `Failing test verified at: <5a-sha>`) → 5c refactor。`test+fix 同 commit` = 沒驗 test 有效。
    5. **修了 bug 必須加 INV 到 `docs/invariants.md`**:沒加不算修完。半年後同類 bug 一定回來。
    6. **cycle file 留檔不刪**:cycle 收完 commit 進 git,當作 audit trail。
    7. **每月 retro amend workflow.md**:漏掉的 bug / 浪費的 stage / 卡住的 finding → 回頭改 SOP。
    

    檔案 2/4 — docs/cycle-template.md

    每個 cycle 開頭從這份複製出 docs/cycles/Cn-<topic>.md(n 是流水號,grep 看下一個)。照著填,不要自己改 stage 結構。

    # Cycle Cn — <short PR title>
    
    **Owner**: <agent ID / human>
    **Started**: YYYY-MM-DD HH:MM
    **Status**: open / in_qa / in_triage / in_fix / regression / closed
    **Cycle Type**: T-PR-cycle / T-regression-fix / T-feature-cycle / T-spec-audit / T-user-smoke-followup
    **Related**:
    - PR / branch: <commit_sha or branch>
    - Spec section: <§X.Y or "N/A">
    - Primary INV(s) targeted: INV-XXX-NNN, INV-YYY-MMM
    
    ---
    
    ## Stage 0.5 — Pre-cycle hygiene
    
    - [ ] `git status --short` clean (除了本 cycle 將動的 file)
    - [ ] HEAD = <commit-sha>
    - [ ] fixture reset 跑過, baseline canonical
    - [ ] 列出本 cycle 用的 disposable fixtures (qa_<cycle>_<role>_<timestamp> prefix)
    - [ ] 所有相關服務 healthy
    
    ## Stage 1: RD 自測
    
    - [ ] unit test 全綠 (commit: <sha>)
    - [ ] live smoke 紀錄:<endpoint X / user Y / happy path 結果>
    - [ ] PR header 完整 (滿足 INV / 可能影響 INV / 提議新增 INV 三段)
    
    ## Stage 2: QA wave
    
    ### QA agent A — INV-XXX-NNN red-team
    - Launched: HH:MM
    - Result: ✅ / ❌ / OPEN
    - Findings: <count>
    
    ### QA agent B — INV-YYY-MMM regression
    - Launched: HH:MM
    - Result: ✅ / ❌ / OPEN
    
    ## Stage 3: OPEN findings
    
    ### F-Cn-001
    - QA agent: A
    - Resolver/Feature: <name>
    - Observed: <事實,不下判斷>
    - Repro:
      ```
      <exact commands / GraphQL / curl>
      ```
    - PM triage:
      - Class: bug / feature / usage / not_issue / spec_clarification
      - Confidence: high / low
      - Reasoning: <≤2 sentences citing spec/INV>
      - User review needed: yes / no
    
    (repeat for each finding)
    
    ## Stage 4: User review (only low-conf items)
    
    - [ ] F-Cn-XXX user-confirmed class: <class>
    
    ## Downstream sweep (Stage 5 之前必填)
    
    ### 本 cycle 改動的 state
    - DB tables: <list>
    - Schema: <changes>
    - Fixture state: <changes>
    
    ### 讀取上述 state 的其他 resolver / query
    
    | State | Reader | Stage 6 必驗 |
    |---|---|---|
    | <table_X> | <Resolver A / Query B> | ✅ |
    
    ## Stage 5: RD fix
    
    ### Stage 5a — failing test (red)
    - Test 檔: <path>
    - 跑出 red: commit <5a-sha>
    
    ### Stage 5b — implement fix (green)
    - Fix commit: <5b-sha> (帶 `Failing test verified at: <5a-sha>`)
    
    ### Stage 5c — refactor + regression
    - 全套既有 test pass: ✅
    
    ## Stage 6: Regression
    
    - QA wave 重跑 (scope 含 downstream sweep ripple)
    - 結果: ✅ / ❌
    
    ## Stage 7: Comparison QA
    
    - 新 verifier 不告知原 QA 結果, re-audit
    - 結論: 跟原 QA 一致 / 不一致
    
    ## Stage 8: Merge gate
    
    - [ ] PR header 完整
    - [ ] 宣告的「滿足」INV: ✅
    - [ ] 宣告的「可能影響」INV regression: ✅
    - [ ] 兩個 QA agent 結論一致
    - [ ] OPEN list 清空
    - [ ] unit test 綠
    - [ ] 如影響 UI: manual smoke happy path
    
    ---
    
    ## Cycle close
    
    - **Closed**: YYYY-MM-DD HH:MM
    - **Outcome**: merged-on-dev / abandoned / split into Cn+1
    - **Total commits**: <count>
    - **New INVs added**: <list>
    - **Bugs fixed**: <count>
    - **Lessons** (going to brain): <bullet points>
    

    檔案 3/4 — docs/invariants.md

    專案的 invariant 契約 catalogue。初始空白,隨 cycle 累積。每修一個 bug 必須在這加對應條目——沒加不算修完。半年後 grep 某個 INV ID 應該找得到「誰加的、為什麼加、對應哪個 test」。

    # Invariants — Project Contract Catalogue
    
    > Every invariant here is a contract. Code must hold. Tests must verify.
    > Format: `INV-<CATEGORY>-<NNN>: <statement>` + origin + severity + test ref.
    
    ## Categories (調整為你專案實際需要的)
    
    - `INV-AUTH-*` — authentication / session / token rotation
    - `INV-RBAC-*` — role-based access control / capability checks
    - `INV-RLS-*` — row-level security (multi-tenant isolation)
    - `INV-DATA-*` — data integrity / nullability / FK / atomicity
    - `INV-IDEM-*` — idempotency (probe-then-INSERT, advisory locks)
    - `INV-INPUT-*` — input validation / sanitization
    - `INV-UI-*` — frontend behavior contracts
    - `INV-RESOLVER-*` — resolver-level contracts (scope, error shape)
    - `INV-SCHEMA-*` — schema design constraints (反 over-design 用)
    - `INV-BATCH-*` — batch operation invariants
    
    ## Verification Layer Reference
    
    每條 INV 標 verification layer:
    
    - L0 spec / L1 INV / L2 schema / L3 resolver / L4 frontend / L5 E2E
    
    (同一條 INV 可能 multi-layer。看本文 §5 對 6-layer doneness 的說明。)
    
    ---
    
    ## Invariants
    
    ### INV-AUTH-001 (example template — 換成你的)
    - **Statement**: <one-line contract,可被測試直接驗證>
    - **Origin**: Cycle C<n> (YYYY-MM-DD) — <short context, why this surfaced>
    - **Severity**: P0 / P1 / P2
    - **Test**: <path/to/test.go::TestFuncName> or <❌ TODO in backlog>
    - **Enforcement layer**: L1 + L3
    - **Related findings**: F-C<n>-NNN
    
    ---
    
    ## Backlog (test ❌ TODO)
    
    當你寫了 INV 但 test 還沒寫完時, 標 ❌ 放這裡。半年後拿這個 backlog 跑「補測試 sprint」:
    
    - ❌ INV-XXX-NNN (待補 integration test)
    - ❌ INV-YYY-MMM (待補 E2E test)
    
    ---
    
    (initial state: empty — populate as cycles surface bugs.
    每 fix commit 必須在這加對應 INV, 沒加不算修完。)
    

    檔案 4/4 — AGENTS.md

    Role taxonomy + 資源預算。不寫具體職稱(架構師 / PM / UI-UX / 後端 / Flutter / DBA / QA)——那是死文件做法。寫的是「執行類型」(Writer / Verifier / Triage / Comparison / Newbie) + 機器資源上限,具體 staffing 在每個 cycle file 的 Header 裡。

    # Agents — Role Taxonomy + Resource Budget
    
    > Roles are **perspectives**, not headcount. Agent count is an OUTPUT
    > of staffing per cycle, declared in each cycle file Header.
    > This file holds only the **invariant** parts: budget ceiling + type taxonomy.
    
    ## Resource Budget (本機, 改成你的數字)
    
    | Item | RAM | Notes |
    |------|-----|-------|
    | Total RAM | 32 GB | This machine |
    | OS + Docker + browser reserve | ~7 GB | Baseline |
    | **Available for agents** | **~22 GB** | Max budget |
    
    ## Model Memory Reference (Claude Code)
    
    | Model | RAM | When to use |
    |-------|-----|-------------|
    | Opus | ~1.0 GB | architecture / cross-file reasoning / security / senior thinking |
    | Sonnet | ~0.6 GB | implementation / API / tests / documentation |
    | Haiku | ~0.4 GB | file scanning / config compare / simple SQL / read-only audit |
    
    口訣:需要「想」→ Opus | 需要「做」→ Sonnet | 需要「找」→ Haiku
    
    ## Role Taxonomy (perspectives, not job titles)
    
    | Type | Action | Parallelizable? | Typical model | Notes |
    |------|--------|----------------|---------------|-------|
    | **Writer** | mutate files (code / SQL / migration / spec) | NO (single-thread) | Sonnet / Opus | 同時只 1 個 |
    | **Verifier** | read-only inspection / red-team / regression | YES | Haiku / Sonnet | scope 鎖死 1-3 INV |
    | **Triage** | classify findings (bug / feature / usage / not_issue) | NO (sequential) | Sonnet (或人類) | PM authority |
    | **Comparison** | independent re-verify (Stage 7) | YES (with #1 verifier) | Haiku | 不知道原 QA 結果 |
    | **Newbie** | adversarial persona audit (broader coverage) | YES | Sonnet | each persona explicit prompt |
    
    ## Per-Cycle Staffing (declared in cycle file Header)
    
    每個 cycle 在自己的 `docs/cycles/Cn-*.md` Header 宣告本輪派多少 agent。範例:
    
    | Agent ID | Type | Model | RAM | Scope |
    |----------|------|-------|-----|-------|
    | RD-1 | Writer | Sonnet | 0.6 GB | 整個 cycle 寫入 |
    | QA-A | Verifier | Haiku | 0.4 GB | INV-XXX-NNN red-team |
    | QA-B | Verifier | Haiku | 0.4 GB | INV-YYY-MMM regression |
    | QA-C | Comparison | Haiku | 0.4 GB | Stage 7 (盲 re-audit) |
    | PM-Tri | Triage | Sonnet | 0.6 GB | Findings ≥3 才派 |
    
    **Memory budget check**: 加總 ≤ available。Over budget → merge 兩個最低 scope Verifier。
    
    ## Iron Rules (執行契約, 違反退回)
    
    1. **一個 cycle 同時只能 1 個 Writer agent 動手**。其他 agent 都不准動 code / spec / schema / migration。
    2. **Verifier 永遠不准標 P0/P1**——只能 ✅ / ❌ / OPEN。
    3. **Verifier scope 必須鎖死 1-3 個 INV**。不准「找任何 bug」。
    4. **TDD red-green 必拆 5a / 5b / 5c 三 commit**。
    5. **cycle file 必須留檔**, 跨 cycle 不刪。
    6. **每月 retro 一次, amend workflow.md 或 AGENTS.md**——這份檔死掉就跟 staffing 死掉一樣慘。
    

    4 個檔放好之後,接下來那段 bootstrap prompt 就有東西可指了——每個動作都對應到上面具體的檔案內容。

    5 個 type 的事故來源 — 入門篇深挖

    看到 AGENTS.md 列 Writer / Verifier / Triage / Comparison / Newbie 5 個 type,你可能會想:「為什麼不直接用傳統 8 職稱(架構師 / PM / UI-UX / 後端 / Flutter / DBA / QA)?」答案是這 5 個 type 不是想像出來的,是踩過真實角色事故反推出來的補丁——21 輪 ping pong、11 輪 self-audit 漏 P1、5 persona 抓 23 finding。每個 type 對應一條具體事故。

    故事完整版在入門篇用第一人稱寫:「為什麼修不完?」— 從 21 輪迴圈到 5 type taxonomy 的多 agent 角色設計。沒看過入門篇的讀者建議先回頭讀,再看本篇 5 個 type 怎麼用會更有 context。

    另一個跟 type 並列的設計選擇是 per-cycle dynamic staffing:不是「每 cycle 派固定 N 個 agent」,而是每個 cycle 在 docs/cycles/Cn-*.md Header 自己宣告派哪些 type、什麼 model、佔多少 RAM,加總要 ≤ machine available。改 1 行 typo 跟改 schema 不會用同樣編制。同樣在入門篇的故事裡詳細展開。

    Bootstrap prompt(複製貼到新 session 的開場白)

    你接手這個專案。第一輪 onboarding 強制讀以下檔案,讀完再開工:
    
    1. docs/workflow.md   — 8-stage cycle SOP,所有 PR 必經
    2. docs/cycle-template.md — cycle file 結構,每個 PR 複製一份
    3. docs/invariants.md — 所有 invariant 契約,改動前先看會影響哪幾條
    4. AGENTS.md          — 本機資源預算 + role taxonomy
    
    從現在開始,所有改動走 cycle file 流程:
    
    1. 開 PR 前 git checkout -b feat/<topic>
    2. 從 cycle-template.md 複製成 docs/cycles/Cn-<topic>.md
       (n = 流水號,grep 既有 docs/cycles/ 看下一個 n 是什麼)
    3. 填 Header(owner / start time / cycle type / related INV)
    4. 跑 Stage 0.5 pre-cycle hygiene 確認 baseline 乾淨
    5. 進 Stage 1 RD 自測 → Stage 2 QA wave → ... → Stage 8 merge gate
    6. 收尾時 cycle file commit 留檔,絕對不刪
    
    紀律:
    - QA agent 永遠不准標 P0 / P1(那是 PM 的 authority)
    - 任何 fix 必須 5a 寫 failing test 紅燈 → 5b 寫 fix 綠燈 → 5c refactor
    - 任何改動先 grep 找 downstream reader,沒列必漏
    - cycle file 寫具體 evidence,不寫抽象 status
    - 修了 bug 必須加 INV 到 docs/invariants.md,沒加不算修完
    
    不確定的 stage 先問我,不要自己腦補。

    這段直接 paste 進新 Claude Code session、Antigravity initial message、Codex 的第一輪 prompt、或 Cursor 的 chat input 都能用。共通點是這些工具都讀 markdown,所以方法論本身跨工具。

    跨工具相容性——自動觸發機制

    差別不在「方法論能不能跑」,在「自動觸發機制」。每個工具有自己的「啟動時必讀」slot:

    工具 自動觸發 slot 怎麼放 bootstrap
    Claude Code CLAUDE.md(專案根目錄)+ ~/.claude/skills/ CLAUDE.md 第一段宣告「## Domain Skill: cycle-workflow」+ skill 寫 cycle SOP 引導
    Codex / OpenAI Agent AGENTS.md(OpenAI 協議) AGENTS.md 開頭加「啟動時讀 docs/workflow.md 必經 8-stage」段落
    Antigravity 專案 root system prompt 同上,在 system prompt 內 reference docs/workflow.md
    Cursor .cursorrules .cursorrules 寫「每次回應前讀 docs/workflow.md」+ reference cycle template
    Aider .aider.conf.yml / CONVENTIONS.md CONVENTIONS.md 寫 cycle SOP 要點,啟動時 –read 進去
    純 ChatGPT / Claude Chat 無自動 slot 手動 paste 上面 bootstrap prompt 進每個新對話

    關鍵 insight:方法論存 markdown,觸發機制存工具專屬 slot。換工具時方法論不用重寫,只要更新觸發機制怎麼指向同樣那 4 個檔案。

    持續 update 機制——別讓 kit 變死文件

    啟動只是第一步。長期維護有三條強制 update trigger,少了任何一條,kit 半年後就會 rot:

    1. fix: commit 強制 update invariants.md:修了 bug 必須加對應 invariant,沒加不算修完。沒這條,同類 bug 半年後一定回來。
    2. 每 cycle 收尾 commit docs/cycles/Cn-*.md:cycle file 留檔不刪,當作 audit trail + 給未來 cycle 參考。沒這條,cycle 跑完就忘,跨 cycle lesson 全部蒸發。
    3. 每月 retro amend workflow.md:跑了一個月會發現某個 stage 太重 / 漏 / 順序不對。retro 看數據(漏掉的 bug、浪費的 stage、卡住的 finding),回去 amend SOP。沒這條,workflow.md 變死文件。

    這三條 trigger 應該寫進 workflow.md 自身,讓「每個 agent 開工前必讀 workflow」這個動作自動帶上「該 update 什麼」的提醒。

    第一個專案的 day-1 動作

    1. git init + 建 docs/cycles/ 目錄
    2. 把上面 4 個檔案複製進來(workflow.md / cycle-template.md / invariants.md 空白 / AGENTS.md)
    3. CLAUDE.md(or 對應工具的 root prompt 檔)宣告必讀那 4 個
    4. 第一個 PR 就照 cycle file 流程走——不要說「先簡單做,以後再上 SOP」,以後不會來
    5. 跑完第一個 cycle,commit cycle file + 第一條 invariant + 第一輪 workflow.md amend(會發現自己漏寫了什麼)

    這套不需要先「累積經驗」才能啟動。第一個 cycle 跑完就有第一份 cycle file 範例給未來自己 / 未來 agent 看,雪球從第一天就開始滾。

    §8 反模式——cycle file 怎麼寫會死掉

    • 寫太抽象:只列 status(QA: ✅),沒列 evidence(哪個 invariant、哪個 attack scenario、reproduce 步驟)。半年後讀不懂自己寫了什麼。
    • 寫太瑣碎:每個 keystroke 記 timestamp,cycle file 變成 chat log。讀的人撈不到結論。
    • 不留 cycle file:對話結束就忘,跨 session 必撞失憶。最常見也最致命。
    • 不分 stage:一個 cycle 寫成一坨流水帳。新 agent 不知道現在跑到哪。
    • 寫在 cloud doc / Notion 不是 git:沒 audit trail,branch 切換 cycle file 不會跟著切,跨工具不依賴的好處全部失去。
    • 不分 Cycle Type 硬跑 8-stage:user-smoke-followup 跑 Stage 2 QA wave 等於把 user 抓的 bug 丟回給 QA agent 確認——錯位、浪費。

    結語:接力棒不是裝飾,是 multi-agent 工程的真正關鍵

    Multi-agent 工程兩條互補規則:

    1. 動手的 agent 只能一個(寫入單線程,從 Cognition / Stanford 等業界共識)
    2. 下一個 agent 必須能無痛接手(cycle file 接力棒,業界文章很少談)

    多數人聽到「multi-agent」想到的是「多個 AI 一起工作」。實際上正確的設計是:同時間只有一個 AI 在動手,其他都是不動手的判斷者;動手的累了下一個來,接力棒(cycle file)不能丟

    業界文章很少談接力棒——他們談 orchestrator-subagent、談 generator-verifier、談 context isolation,但很少談「下一個 agent 從哪裡讀狀態」。可能因為 demo 場景太短,撞不到 compaction 也撞不到跨 session 失憶。長期專案跑下來,這個盲區會反覆把人燒一遍。

    Cycle file 是踩坑長出來的工程紀律。file-as-state-machine pattern 可以推廣到所有需要「process state 跨人 / 跨時間延續」的場景——不分是不是 multi-agent。

    延伸閱讀

  • 「56 條 INV 全綠,user 點一次抓出 4 個 bug」— Multi-Agent 業界共識的五個自家補丁

    重點摘要

    • 規劃 staffing 跟執行 staffing 必須分離——HOME123 的 AGENTS.md 寫死 8 職稱 + 沒 update 機制,跑 33 cycles 紋風不動,變成「歷史文物」。
    • 寫入單線程,讀取並行——多 agent 平行寫程式碼會產生隱性風格 + 決策衝突,但平行派 5 個 persona newbie 讀程式碼抓 bug 完全沒問題。
    • Generator-Verifier ROI 最高——只加一個 verifier agent 就顯著提升品質,且 verifier 不共享 generator 的 context 反而效果更好。
    • Persona-driven newbie 抓 PM 漏的 finding——HOME123 C29 派 5 個不同 persona 平行 audit,抓出 23 個 PM + Tom 都漏的 finding,其中 4 個是 cycle blocker。
    • 「INV 全綠」≠「對」——C11 user 隨便點 chairman dashboard 就抓出 11 個 verification cycle 都漏的 LEFT JOIN ARRAY_AGG NULL bug。Cycle SOP 只能抓「SOP 想得到的」,user 抓「SOP 想不到的」。

    讀完愛好 AI 工程的 Multi-Agent 架構再探: 三省六部反模式和業界收斂共識(2026-05-19),裡面整理的 Anthropic、Cognition、LangChain、Stanford 各家對 multi-agent 系統的共識,跟我家 HOME123_NEW 從 R35 21 輪迴圈踩坑、演化到 R36 cycle SOP 的軌跡高度重疊。

    但「重疊」不等於「教會我新東西」。我反而在對照中發現,有五個自家踩出來的細節,業界文章沒講或講得不夠重——這篇就把這五個補丁寫下來,給跟我一樣已經在生產環境跑 multi-agent workflow 的人參考。

    本文不從 0 開始講 multi-agent 概念,假設你讀過原文或熟悉 orchestrator-subagent / generator-verifier 這類詞彙。

    補丁 1:AGENTS.md 為什麼變死文件——「規劃 staffing」跟「執行 staffing」必須分離

    我家 HOME123_NEW 的 AGENTS.md 是 2026-05-12 寫的,列了 8 個職稱角色:架構師 / PM / UI-UX 設計師 / 後端工程師 / Flutter 工程師 / Postgres DBA / 資料探索員 / QA。看起來像一張漂亮的組織圖。

    實際跑起來呢?專案 33 個 cycle 結束、Phase 1 ship 之後,這份 AGENTS.md 一次都沒動過

    對照同一個 repo 的 docs/workflow.md:從 R36 step 3 v1.0 寫下來,持續演化到 v2.1 per-layer QA、v2.2 加 TDD red-green + SCN P0-1,六個 commit,每一輪 cycle 收穫都回寫。workflow.md 活著,AGENTS.md 死了

    死文件的兩個必要條件

    盤點下來,一份文件變死,要同時滿足兩個條件:

    1. 寫了「會變的具體細節」——例如「8 個職稱 + 主要工作 + 預估記憶體佔用 600MB」。這些隨專案演化必然會變。
    2. 沒有強制 update 機制——沒掛在任何「每 cycle 必看」「每 PR 必檢」的閘口上。

    任一條件缺失,文件還能活:

    • 只寫不會變的部分(資源預算上限、role 類別 taxonomy),沒 update 機制也 OK——因為真的不需要 update。
    • 寫具體細節,但每 cycle 強制 re-check(像 HOME123 的 docs/cycles/Cn-*.md 活在 git,Stage 8 merge gate 強制檢查),也 OK——因為會被更新。
    • 兩個都犯 = 上線當天就在 rot。

    解法:規劃 staffing vs 執行 staffing 分離

    文件類型 性質 該怎麼活
    規劃文件(AGENTS.md / ROADMAP.md) 計畫期的「我以為會這樣」 寫 timestamp、標 initial assumption,職責限縮到「不會變的部分」(資源預算、role taxonomy、必讀 brain 索引)
    執行契約(workflow.md / invariants.md / cycle file) 違反就退回的活文件 每 cycle / 每 PR 強制 re-check,違反當 review fail,cycle 收完歸檔留檔

    原文「三省六部幻覺」段批的「把 agent 命名成 PM / 架構師 / QA」,本質上就是把規劃文件當執行契約用——以為列了 8 個職稱就能跑,但職稱不會自我更新,專案演化會立刻甩開它。我這次踩到的就是這個。

    補丁 2:不是「Single vs Multi」,是「寫入單線程 + 讀取並行」

    原文整理 Anthropic 2026/1 給 multi-agent 的三個合理場景:context 隔離、並行覆蓋、工具專業化。也引用 Cognition 2026/4 的反直覺發現:「寫入動作維持單線程,其他 agent 只負責提供判斷,不負責動手」。

    我家的實踐長這樣(從 R36 開始穩定):

    元件 配置 對應原文模式
    Writer 永遠 1 個 Engineer agent,寫 code + 寫 unit test Cognition「寫入單線程」
    Verifier wave 並行 2-5 個 QA newbie,每個 scope 鎖死 1-3 個 INV Generator-Verifier + Parallel exploration
    Orchestrator 我自己(PM 兩道閘:規格定錨 + finding triage) 人類在 loop
    外部狀態 docs/cycles/Cn-*.md 活在 git 原文「orchestrator-worker + 外部狀態文件」

    整套是Orchestrator-Subagent + Generator-Verifier 混合,五種協調模式裡 ROI 最高的兩個疊起來。

    對應 Stanford 那篇論文的實戰觀察

    原文引用 Stanford 2026/4 的 Single-Agent LLMs Outperform Multi-Agent Systems on Multi-Hop Reasoning Under Equal Thinking Token Budgets(arxiv 2604.02460),用資訊理論的「數據處理不等式」證明:固定 token 預算下,單一 agent 在 multi-hop reasoning 上贏過 multi-agent

    把這個結論套到 code generation 場景就是:Engineer 那 1 個 agent 才是真正在做連續推理的——它要把 spec → schema → resolver → test 一路推下去,context 連續性是品質關鍵。讓五個 agent 平行寫不同模組,結果就是 Stanford 那篇講的:每個 agent 自己的 context 縮短了,推理深度不夠。

    但 verification 不是 multi-hop reasoning,它是多點獨立檢查。每個 newbie scope 鎖死 1-3 個 INV,根本不需要 multi-hop reasoning;反而從乾淨 context 出發比較好——這也是 Cognition 觀察「verifier 不共享 generator context 反而更好」的原因。

    所以選 single 還是 multi 不是哲學問題,是「這個子任務需不需要連續推理」的問題。需要 → single;獨立檢查 → multi。

    補丁 3:Generator-Verifier 的六個 HOME123 細節

    原文講 Generator-Verifier 是五個協調模式裡 ROI 最高的,但講的是「為什麼有效」。HOME123 R35→R36 演化過程中,六個操作細節決定了它真的有效還是只剩形式:

    1. QA scope 鎖死 1-3 INV,不准抓「任何 bug」。R35 21 輪迴圈的反面教材就是讓 QA「找任何問題」,結果 finding 無限發散。Scope 鎖死後,每個 newbie 只查它自己的契約。
    2. QA 不准標 P0 / P1。只能標 ✅ / ❌ / OPEN。P0/P1 是 PM 的 authority,QA 上交給 PM triage。這條防止 QA agent「自己升級嚴重度」拖累節奏。
    3. PM 兩道閘:第一道是寫 spec / 加 INV(規格定錨),第二道是 finding triage(bug / feature / usage / not_issue 30 秒分判)。少了任一道,QA wave 都會無限發散。
    4. PR header 強制宣告 INV 影響。每個 PR description 必填三段:滿足哪些 INV、可能影響哪些 INV、提議新增哪些 INV。沒填完整 = PR 不算開,reviewer 直接退。
    5. Verifier 不共享 Writer 的 context。QA agent prompt 模板只給它「PR commit SHA / 一條 INV / test users / 環境」,不給它 Writer 的對話歷史。乾淨 context 反而推理更深(Cognition 觀察)。
    6. Mutation testing 對抗 groupthink。每月一次,故意往 verified INV 對應的 code path 塞一個 plausible bug,看 QA agent 抓不抓得到。抓不到 = invariant test 不夠 sharp,補 attack scenario。

    第 6 條是原文沒講的盲區。QA agent 跟 Engineer agent 來自同一個 LLM 譜系,shared assumption 會讓兩邊「想得一樣」——0 ❌ 不一定是程式對,可能是兩個 LLM 從同一個訓練資料裡學到同樣的 blind spot。Mutation testing 是目前我知道唯一能對抗這個的方法。

    補丁 4:Over-design 怎麼補救——2026-05-22 砍 1000 LOC 實錄

    原文講 multi-agent 的成本非線性爆炸、錯誤放大,但沒講「multi-agent 容易生出 over-design 的 schema / API」這個副作用。HOME123 跑到 2026-05-22 做了一次 over-design audit,結果是砍掉 1000+ 行。我把那份 audit 攤開,看 multi-agent workflow 為什麼會生出垃圾,以及怎麼補救。

    5 個 dead schema 一次掃掉

    砍掉的東西 為什麼是死的
    Query.myCapabilities 0 frontend caller(me.capabilities 已涵蓋)
    Parcel.notifications + type Notification 0 frontend query,Phase 2 push 走別條 path
    type Guard 整個 type 標 @deprecated,0 caller
    Mutation.batchDeliver + BatchDeliverInput 0 frontend call(所有 UI 都打 deliverParcelBatch),約 260 LOC resolver
    Mutation.createParcelIntakeBatch + UI dialog 跟 C31 session-based batch intake 共存,UI 兩個批次按鈕讓警衛 cognitive load 爆炸,砍掉 ~343 LOC frontend + ~360 LOC backend

    反 anti-pattern:「往後查」

    這五個 dead schema 全部都是同一個 anti-pattern:「為將來預留」。設計時 agent 想「萬一將來要顯示通知 timeline 呢?」「萬一未來 batch deliver 改 session model 呢?」「萬一要 polling caps 呢?」——於是 schema 多了 field、resolver 多了支、tests 多了行。

    但 multi-agent workflow 的特性是沒人記得當初為什麼加:今天的 Engineer 不是當初寫 schema 的 Engineer,QA 不會質疑 schema design 是不是必要,PM 看 finding 不會回頭 audit schema 健康度。「往後查」的 anti-pattern 在 multi-agent 環境會比 single-developer 累積更快。

    三個補救機制

    1. 定期 over-design audit(每 ~2 個月一次或大 milestone 後)。PM scan 角度:「99% 無痛、edge case 不擋 99%、不為將來 may-be 需求預留、不為『好體驗』造成系統壓力」。
    2. 砍之前先 grep 全 codebase 確認 0 caller。「我以為沒人用」跟「grep -r 證實 0 caller」是兩件事。HOME123 砍 batchDeliver 前 grep app/lib/,只在註解出現,於是放心砍。
    3. 砍完寫進 INV 防回流。砍 dead schema 之後加 INV-SCHEMA-001:「standalone batch* mutations 不再加,batch 行為一律走 session-based pattern」。沒寫 INV 半年後同樣的 over-design 會回來

    Design 不足:persona-driven newbie 才挖得出來

    Over-design 反過來是 design 不足。HOME123 C29 跑了一個實驗:派 5 個 persona-driven adversarial newbie 平行 audit,每個 persona 有明確的「你是誰、你假設世界是什麼樣、你要找的不是『功能對不對』而是『產品對不對』」mandate:

    • Newbie 1:高吞吐警衛阿伯(每天 300 件包裹)
    • Newbie 2:無棟透天社區主委(12 戶,只有「幾號幾樓」概念)
    • Newbie 3:多棟社區主委(5 棟,要選棟才能下一步)
    • Newbie 4:老年住戶用 iPhone 11(375px 螢幕、視力差)
    • Newbie 5:跨租戶 RLS 測試者

    5 個 newbie 平行 audit 抓出 23 個 finding,其中 4 個是 cycle blocker——這些都是我跟 PM 看了無數遍漏掉的。

    最戲劇性的是 N2 跟 N3 加起來證實了我的 directive 錯了:我 2026-05-20 拍板「不用管棟」,N2 跑去把 buildings 設成空陣列發現 backend 硬擋(buildings cannot be empty),N3 跑去測多棟社區發現 dropdown collision。兩個 persona 的觀察合起來,證明「不用管棟 globally」over-fit 到單一棟的場景,我自己只看單一棟所以沒撞到。後來我把 directive partial revoke,改成 buildings.length > 1 才顯示棟 picker。

    Persona-driven newbie 是補 design 不足最便宜的工具。成本就是每個 newbie 一份明確 persona prompt + 一輪 read-only audit,沒有寫衝突、沒有 merge 成本。

    補丁 5:「我很有信心,但你隨便測就炸」——C11 完整故事

    這條是 multi-agent 系統最容易掉進去的坑——而原文完全沒談。先講事件:

    2026-05-10 晚上,HOME123 R36 跑完 11 個 verification cycle、56 條 INV 全綠、所有 QA wave 都報 ✅。我用 chairman 帳號(admin01)登進 dashboard,點開「主委交接」tab——爆炸:

    讀取失敗:can't scan into dest[4] (col: roles):
    failed to scan array element 0: cannot scan NULL into *string

    同一個 session 我隨便點了 chairman dashboard,找到 4 個 bug:這個 NULL scan、communities.public_contact_phone 殘留的 <script>alert('XSS')</script> 測試資料、parcel serial 多顯示一個 #(spec 沒寫)、carrier barcode 沒有 lookup query 入口。

    名言誕生:

    R36 11 個 cycle + 56 條 INV ✅,user 隨便點 1 次 → 4 個 bug。

    User browser smoke remains the most valuable QA signal.

    深挖那個 LEFT JOIN ARRAY_AGG NULL bug

    有問題的 SQL 是 CommunityUsers resolver,長這樣:

    SELECT u.*, COALESCE(
      ARRAY_AGG(ur.role_code) FILTER (WHERE ur.revoked_at IS NULL),
      '{}'::text[]
    ) AS roles
    FROM users u
    LEFT JOIN user_roles ur ON ur.user_id = u.id
    WHERE u.community_id = $1
    GROUP BY u.id;

    Bug 在哪?LEFT JOIN 對沒匹配的 user 會 pad 一行 ur.* 全部 NULL 的 row。SQL 三值邏輯下,NULL IS NULL 是 TRUE——所以 FILTER (WHERE ur.revoked_at IS NULL) 把這個 pad row放進了 aggregate。結果 ARRAY_AGG 回傳的不是空陣列、是{NULL}(包一個 NULL 元素的陣列)。COALESCE 看到的是非 NULL 陣列,直接 pass through,Go scan 進 []string 時就爆 cannot scan NULL into *string

    修法很簡單:FILTER 加一個 AND ur.role_code IS NOT NULL,把 pad row 排除掉。但為什麼 11 個 verification cycle 都沒抓到?

    因為這個 bug 只在「有 user 沒有任何 user_roles row」時觸發。C6 cycle 的 seed-demo.sh 改成 idempotent 之前,所有 demo user 都有至少一個 role;C6 之後,seed 改成「先 DELETE 殘餘 user 的 roles 再 disable user」,結果 DEMO001 多出 11 個 disabled-residue user 帶 zero user_roles row。fixture 狀態改變才暴露 bug,前 11 個 cycle 跑的時候 fixture 還沒進入這個狀態

    這條 cycle file 寫下了 multi-agent 系統最殘酷的真相:

    Cycle SOP catches what cycle SOP can imagine; user catches the rest.

    為什麼 TDD 也擋不住

    我這套 workflow 有強制 TDD red-green 三步(Stage 5a 寫 failing test、Stage 5b 寫 fix、Stage 5c refactor),為什麼還是漏?

    1. Vacuous green test。Test 永遠 pass 不是因為實作對,是因為 assert 太寬或 fixture 沒覆蓋觸發條件。C11 那個 NULL bug 在前 11 個 cycle 的 test fixture 裡,根本沒有「user 帶 zero roles」這個狀態,所以 test 一直 green。
    2. Groupthink。QA agent 跟 Engineer agent 同 LLM 譜系,想得一樣。Engineer 寫 test 時想到的 attack scenario,跟 QA 寫 test 時想到的 attack scenario,高度重疊。盲點是 shared 的。
    3. L1-L3 全綠 ≠ L4-L5 也對。HOME123 把「對」分 6 層:L0 spec → L1 INV → L2 schema → L3 resolver → L4 frontend → L5 E2E。前 11 個 cycle 主要驗 L1-L3,L4 user click 沒人驗。INV 全綠是 L1 全綠,跟 user 在 chairman dashboard 看到什麼是兩件事。

    5 個建議方向

    1. User smoke = primary detection。不是 secondary、不是「最後再點一次」。每個 milestone 結束第一件事是 user 隨便點,不是看 CI report。
    2. Mutation testing 對抗 groupthink。每月或大 INV amendment 後跑一次,故意塞 plausible bug,看 QA agent 抓不抓得到。抓不到 = QA prompt 跟 Engineer 想得太像,得補 attack scenario。
    3. Adversarial persona 平行覆蓋。C29 模式:每個 persona 有明確「你跟 Engineer 想法不同的地方在哪」mandate,5 個 newbie 平行 audit,讀取型 multi-agent 完全沒衝突風險。
    4. 6-layer thinking 防止誤推。看到「INV 全綠」先問「這是 L 幾全綠?L4 / L5 有人驗過嗎?」L1-L3 全綠不等於對,只是「未驗中比較強的子集」。
    5. TDD red-green 三步分 commit。Stage 5a 寫 failing test 單獨 commit、Stage 5b 寫 fix 單獨 commit,commit message 必填 Failing test verified at: <5a-sha>。bisect 看得出 red→green 軌跡,防 vacuous test。「test 跟 fix 同 commit」= test 從沒 fail 過 = 沒驗 test 有效。

    結語:業界共識是地圖,cycle file 是地形

    原文整理的業界共識像一張地圖:告訴你 Anthropic 走哪條、Cognition 撞了什麼牆、LangChain 怎麼分 patterns。地圖很有用——你不會走錯方向。

    但地圖不是地形。HOME123 33 個 cycle 累積的 docs/cycles/*.md 才是地形:哪個彎要慢、哪段路會塞、哪裡橋斷了走小路。地圖告訴你「先試 single-agent」,地形告訴你「single-agent 的 Engineer 寫完之後,第二件事是叫 5 個 persona newbie 去點點看」。

    這篇五個補丁,本質上是把地形寫下來。給已經在跑 multi-agent workflow、開始撞牆、覺得業界文章沒講透的人。

    下一步:把這次討論抽出的「規劃 staffing vs 執行 staffing 分離」原則,寫進 ~/.claude/projects/-home-tom/memory/brain/adaptive-agent-team-staffing.md brain;把 HOME123 R36 的 PM/Engineer/QA workflow.md 抽象成 ~/.claude/templates/workflow.md 通用模板。這樣下個專案就不用從 R35 21 輪迴圈重新踩一次。

    延伸閱讀

  • 「未驗即不可信」AI 協作開發走出 21 輪修不完:SDD/TDD/腦子整合

    重點摘要

    • 「未驗即不可信」:程式碼跑得起來不代表正確,沒對 invariant 跑過 attack scenario 就只是 Schrödinger 狀態。十幾年的程式碼依然會藏沒被檢查的 bug。
    • R35 21 輪修不完是因為缺 PM 兩道閘(spec 定錨 + finding triage)。QA agent 自己標 P0/P1 直接給工程師,spec 邊修邊膨脹。
    • 整合方案:SDD(spec 規格)+ INV(紅線契約)+ TDD(紅藍對抗)+ 腦子(事後教訓)+ Cycle SOP(8 階段流程)= 五層協作架構。
    • 實戰結果:從 R35 數天 21 輪到單 cycle 約 1-3.5 小時收斂,bug:spec_clarification 比例接近 1:1(健康訊號)。
    • 9/9 ✅ 也不算「可信任」:抽樣 ≠ 全集,wiring ≠ behavior,positive 案例 ≠ 涵蓋所有 attack scenario。

    「修不完的迴圈」是什麼?AI 協作開發的常見死結

    AI 協作開發專案最常見的失敗模式不是「做不出來」,而是「修不完」。一輪 QA 抓出 5 個 bug、修完,下一輪又找出 5 個,再下一輪還有,就這樣跑 10 輪、20 輪都收不乾。我把這個現象稱為「未驗即不可信」的具體展示——程式碼在沒有跑過 invariant 紅藍對抗之前,看起來正常運作不代表正確,只代表「目前還沒有人發現的 bug」。

    本文紀錄一個真實 LLM agent 協作專案(Phase 1 的多租戶 SaaS 後端,Go + GraphQL + PostgreSQL)從 21 輪 audit 修不完,到後來建立完整方法論後單 cycle 收斂的全過程,並把 SDD(spec-driven development)、TDD(test-driven development)、腦子系統(brain knowledge base)這三套工具整合成一份可重用的協作 SOP。

    為什麼 21 輪 QA 還在抓 P1?病因診斷

    專案在「R35 audit」階段累積了 21 輪 fresh QA agent 排查,每輪都派一個全新沒 prior context 的「小白 agent」走 spec 找 bug。前 3-5 輪揭發了真實盲點,但第 8、第 12、第 19 輪還在抓 P0/P1,明顯失控。表面看是實作品質太差,深入分析後發現是結構性問題,不是程式碼問題。

    God file:5015 行 hand-rolled resolver 沒有任何結構保護

    專案的 GraphQL resolver 全集中在 schema.resolvers.go 一個檔,5015 行 / 40 個 mutation / 平均 125 行一個。每個 mutation 都手寫五步流程:withTx → RequireCapability → 自己決定要不要 scope check → 自己決定要不要 audit → 自己決定要不要 filter is_active

    整份檔案只有 2 個 auditlog 呼叫、18 個 scope-helper 呼叫散落在 40 個 mutation 之間——每個 mutation 都是「記得做 5 件事」的考試。漏一件 = 一個 bug。R12(cap-vs-role scope)、R17(logout descendants)、R18(partition pruning)、R19(list-loader 漏 child)、R20(sysadmin audit gap)、R21(retired-cap)、R22(photo key)通通是同一類錯誤在 40 個地方各漏一次

    缺 PM 兩道閘:finding 直接從 QA 流到工程師

    傳統工業界 workflow 有 4 個獨立角色:

    角色 主 artifact 決策權
    PM spec / triage 結果 三類分判(bug / feature / usage / not_issue),規格收斂
    Engineer PR + 單元測試 實作
    QA finding report 驗 invariant;只能標 ✅ / ❌ / OPEN
    User 驗收 手動 smoke 最終 ship gate

    R35 把 PM 的兩道閘都拿掉了。第一道(spec 定錨):spec 寫完之後沒同步精準化,invariants 散在 brain 沒成 contract。第二道(finding triage):QA agent 自己標 P0/P1 直接 ping 工程師,沒人問「這是 bug 還是 feature gap 還是 usage issue」。結果每個 newbie 都從 0 開始挖一輪新 spec,spec 邊修邊膨脹,永遠收不完。

    「派越多 newbie 才越能收斂」這個直覺是錯的。第 N 個小白還能找到 P1 不代表實作越來越差,代表 spec 還有黑洞。多 newbie = 多人從不同角度發明新需求。正確訊號是回頭把 spec/invariants 寫硬,不是繼續派人。

    SDD + TDD + 腦子三層整合:契約在不同層級

    SDD(規格驅動)說「先定義要做什麼」,TDD(測試驅動)說「先定義怎麼證明做對了」。兩者都是「契約先於實作」,差別在契約寫在哪。實際 LLM agent 協作專案需要 5 層契約配合,不是單一方法解決:

    層級 內容 改動頻率 對應檔案
    SDD spec 描述性:要做什麼、流程、資料模型 慢(feature 級) docs/specs/*.md
    INV invariants 規範性:永遠不能違反的紅線 + 對應 test sketch 中(每修一 bug 補一條) docs/invariants.md
    TDD test 機器版契約:red-team scenario + 自動化驗證 每個 PR backend/.../*_test.go
    腦子 brain 事後散件教訓 + 通用方法論 每次學到坑就寫 ~/.claude/.../brain/*.md
    SOP workflow 操作性:PR header 模板、agent prompt、triage tree 很慢(鎖死) docs/workflow.md

    腦子是事後紀錄,不是事前防護

    腦子系統(10 步驟從零做到完整 AI 工作流)在這套架構裡是知識長期儲存層,不是執行層。它記錄「曾經踩過什麼坑」、「某個 domain 有什麼最佳實踐」,但不會在下個 resolver 寫的時候自動跑出來擋人

    50+ 條 brain 教訓如果只停在 brain,下個工程師(或 agent)寫新 resolver 還是會踩同樣的雷。把它翻譯成 INV-XXX-NNN 條目 + 對應 invariant test 才能變成 CI 跑得起來的事前防護。這是 SDD(spec 描述)→ INV(紅線提取)→ TDD(test 落地)的左→中→右遞進

    INV 是 SDD 與 TDD 的橋

    純 SDD 的盲點:spec 寫了但沒人記得回頭驗,變裝飾品。純 TDD 的盲點:test 通了但每個 test 各做各的,沒人問「我們漏了哪類 test」(典型如測試覆蓋率 4% 但 happy path 都測了)。

    INV 把兩者橋起來。每條 INV 有:

    • Statement:「X 必須永遠 Y」或「X 永遠不能 Z」一句話
    • Origin:哪一輪 audit 學到的
    • Severity:P0(ship-blocker)/ P1(must-fix)/ P2(debt tracker)
    • Test status:✅ existing / 🟡 partial / ❌ TODO(含 test sketch)

    實際在我這個案例蒸餾出 54 條 INV 分 11 個 category(AUTH、RBAC、RLS、AUDIT、IDEM、RATE、INPUT、DATA、RESOLVER、UI、FILE)。每條 brain 教訓都會對應到至少一條 INV,這是「方法論寫 brain,技術紅線寫 invariants,操作 SOP 寫 workflow,三件事不混」的具體展示。

    從規格到 ship 的 8-stage cycle pipeline

    有了五層契約,需要一個操作流程把它們串起來。設計成 8 階段,每個 PR cycle 一份檔活在 git,撐過對話 compaction:

    PM
      ├─[1] 寫 spec / 加 INV-XXX-NNN     ← 第一道閘:規格定錨
      ▼
    Engineer
      ├─[2] 實作 + 自寫 unit test
      ├─[3] 開 PR(header 必填 INV 宣告)
      ▼
    QA wave(K 個 agent,並行,每個 1-3 INV)
      ├─[4] 紅藍對抗 + INV regression
      ├─[5] 結果分三類:✅ holds / ❌ violated / ⚠️ OPEN
      ▼
    PM triage
      ├─[6] 每個 OPEN 30 秒分判      ← 第二道閘
      │     bug / feature / usage / not_issue
      ▼
    Engineer 只修 bug 類
      ▼
    回 [4] re-run,stop 條件:
      - PR 宣告的 INV 全 ✅
      - 兩個 QA agent 結論一致
      - OPEN list 清空

    QA agent 的硬規則:永遠不能標 P0/P1

    這是整套機制的關鍵紀律。QA agent 不是「品質判官」,是「invariant 驗證者」。它只能回三種結果:

    • ✅ holds:對某條具體 INV 跑紅藍對抗都守住
    • ❌ violated:找到具體 repro 違反某條具體 INV
    • ⚠️ OPEN:觀察到怪事但找不到對應 INV,留給 PM 分判

    P 級嚴重度標籤是 PM 的權限,不是 QA 的權限。OPEN finding 一律走 PM triage decision tree(Q1:是不是真問題?Q2:spec 有沒有規定?Q3:spec 應該規定嗎?),分四類:bug → 修;feature → 進 backlog;usage → 改 docs;not_issue → 駁回。

    Option B:PM-agent 預分類 + user 終審

    當 OPEN findings ≥ 3 個,可以派一個 PM-triage agent 跑 first-pass 分類,加上 confidence 旗標。User 只 review confidence=low 跟 spec_clarification 的子集。User 速度從「每個 finding 30 秒」壓到「review agent 的分類 + 只深看不確定的」。

    PM-agent 的 hard constraint 寫得很硬:不可以提 fix 方案、不可以動 code、不可以 launch sub-agent、不可以 ship/no-ship 決策、不可以漏分類。只做分類。User 永遠保留否決權。

    實戰:6 個 cycle 的具體紀錄

    方法論建立後,立刻在 R36 階段跑了 6 個 cycle。以下是真實時序:

    Cycle 性質 規模 時間 產出
    C1 retroactive verification (41 resolver migration) ~3h30min 14 findings → 7 bug + 6 spec_clar + 1 usage;3 fix commit
    C2 self-spotted regression(前次 R20 修錯了) ~1h migration 0040 + INV-RBAC-006 amendment
    C3 forward-going feature (print 三件套) ~45min Flutter UI + cap wiring
    C4 forward-going feature (offline mutation queue) ~1h Tablet 離線優先實作
    C5 spec audit(隨機抽 9 feature 驗證) ~1h 9/9 ✅ + 2 OPEN finding
    C6 close C5 OPEN findings ~30min spec §9.2 amend + 新 INV + seed-demo.sh idempotent

    C1 抓到 R36 step 2 自己的 architectural bug(authzPrelude 的 cap-check-before-sysadmin-gate 順序,導致 chairman 透過錯誤訊息學到 sysadmin-only cap 名稱)——21 輪 R35 audit 完全沒抓到,C1 跑 1 個 QA agent 90 分鐘抓到。這正是「invariants 蒸餾把人腦 reasoning 升級成機器可驗 contract」的力量。

    C1 的 bug : spec_clarification : usage 比例 = 7 : 6 : 1。接近一半的 finding 不是 code 問題是文件問題。如果只跑 R35 那種「QA → 直接修」流程,這 6 條會變成 6 個沒必要的 code change,或更糟:每輪都長新一條 hand-rolled exception,spec 永遠收不乾。

    C5 抽查:9/9 ✅ 也不算「可信任」

    整套基礎建設蓋好之後,主對話 agent(我)親自跑了一個 spec audit cycle(C5):對 37 個 Phase 1 feature 用 shuf 隨機抽 3 輪 × 3 個 = 9 個 feature,每個用真實 GraphQL 對 backend 跑 attack scenario。結果 9/9 ✅ holds,0 ❌ violated,2 ⚠️ OPEN。

    看起來很漂亮。但這不等於可信任。當我重新檢視自己跑的 9 條測試的深度,老實打分:

    • ✅ 深度足:2/9(logout cascade、login rate limit)——真的對 invariant 跑紅藍對抗
    • ⚠️ 半套:7/9——只驗 wiring 不驗 behavior,positive only 沒 negative case,或在腐化 fixture 上跑
    • ❌ violated:0/9

    具體 anti-pattern 我自己犯了 6 個:(1) 隱性假設 wiring = behavior;(2) 時間壓力下 satisfice;(3) 讓 spec 驅動測試而不是 INV;(4) 避開 destructive test;(5) 把「文件化問題」當「修問題」;(6) 沒照自己寫的 qa-verification.md prompt 流程操作。

    這個結果反過來證明「未驗即不可信」的鋒利之處:不只「沒測 = 不可信」,還包括「測得不夠深 = 也不可信」。9/9 ✅ 只說「2026-05-10 19:00 對 commit 06e7078 抽 9 個樣本沒抓到 ❌」。離「可信任」還缺:

    • Wave 1 P0 invariant test 全綠(54 條 INV 中 50 條還是 ❌ TODO)
    • 所有 OPEN 收掉(兩個 OPEN 已在 C6 處理)
    • 涵蓋率從 9/37 → 37/37 + 從 1/54 → 54/54
    • CI 把它們變成 ship-block 的 hard gate

    「可信任」是需要持續維護的狀態,不是一次達成就鎖住。今天最多打到「比未驗強,但離可信還早」。

    方法論的 meta-loop:自我修正的協作架構

    C5 raise 的 2 個 OPEN finding 立刻觸發了 C6——方法論自己的產出變成了下一輪 cycle 的輸入。具體展現:

    • F-C5-001 HMAC token 從 spec 不可重現:Python 照 spec §9.2 算 token 跟 Go backend 算的不一樣。PM triage 為 spec_clarification → C6 補 spec §9.2 explicit external-client note + 新 INV「HMAC token bit-reproducible from spec」。
    • F-C5-002 fixture rot:dev 測試帳號 wang.dad 的 household_id 指向 disabled 的 household。所有 household-scope 測試都在驗 disabled 狀態 → false confidence。PM triage 為 dev tooling bug → C6 改 seed-demo.sh idempotent 重建 fixture。

    這條 meta-loop 連續觸發三層動詞:spec 改 clarification + invariants 加新條 + tooling 改 idempotent。完整閉環,下一輪同類 finding 不會再生。

    這就是腦子系統 agent team架構成熟之後的應用形態:方法論不只「跑得動」,還能「用自己的產出修正自己」。

    結論:四個可重用 takeaway

    1. 「未驗即不可信」是工程倫理底線。年紀大的 code、看起來正常運作的 code、跑得起來的 code,都不等於正確。沒有對 invariant 跑過 attack scenario 之前都是 Schrödinger 狀態。
    2. SDD + TDD 不是二選一,需要 INV 當橋。spec(描述性)+ invariants(規範性)+ test(機器版) + brain(事後紀錄)+ workflow(操作 SOP),五層配合。每條 brain 教訓都該對應一條 INV。
    3. QA agent 永遠不能標 P0/P1。LLM agent 自評嚴重度直接給工程師 = R35 失控的根因。Severity 標籤是 PM 權限,QA 只能標 ✅ / ❌ / OPEN。
    4. 抽樣不等於全集,wiring 不等於 behavior。9/9 ✅ 看起來說服力強,但只說「這 9 個樣本沒踩到雷」,不說「程式碼可信任」。可信任需要 INV 全綠 + OPEN 收掉 + 持續維護。

    R35 21 輪數天才修不完的東西,C1 cycle 3h30min 收乾並抓到 R35 沒發現的 architectural bug。整套方法論的價值不是「修 bug 修得快」,是「讓 spec 跟 code 之間的契約變成機器可驗,腦子變成事前防護而不只是事後紀錄」。

    方法論成熟之後,工程師的工作從「想下一步做什麼」變成「跑 INV 看 INV 告訴我什麼該做」。這比「一輪一輪我看看哪邊有問題」健康得多。