Files
ISEP/docs/governance/_draft-claude-ai-v0.5.0.md
Leo 50876ffa4f 治理規範進 docs/:claude.ai 原稿存檔+總管修訂版 v0.6.0+逐條分歧書
leo 交辦:把 claude.ai 寫的治理規範整理進 ISEP,並且「查看是否合理,提出意見⋯⋯
改一版你的版本」。原稿作者看不到 codebase,標籤名/hook 名/既有鐵律有實錯。

三份文件:
- _draft-claude-ai-v0.5.0.md  原稿,一字未改,加存檔標頭
- sdd-gitea-governance.md     v0.6.0 現行版
- DIVERGENCE-v0.5.0-to-v0.6.0.md  我改了哪 14 處、為什麼

修訂重點(實查 2026-08-20 的現場,不是推測):
- 標籤名幾乎全是憑空的:gate/human・s/review・close/*・hub・type/* 現場一個都不存在。
  Human 不改名(leo 08-17 才改過,改名會廢掉他的看板習慣),另加 human/exec 當第二維度。
- 狀態機三態擴成七態:原稿會擠掉 s/triage・s/backlog・s/pending・s/stage,
  而那四個態上掛著 179 張 open 票。s/review 與 s/stage 是兩件事,不可互相取代。
- E1–E16 的 hook 全是憑空命名,改成標註「已有 <實際檔名> / 待建」——
  E14 其實已經有了(subagent-claim-worksheet.sh),重造就是第 42 支互相打架的閘。
- 刪掉「薄殼只裝 shell-safe 子集」:那是舊薄殼模型的殘留,正是 InkStoneCo#57 的成因,
  而且與原稿自己的 P11.2.1/P11.2.4 自相矛盾。
- 排程 job 第一版一律不依賴 Gitea Actions runner(有沒有 runner 未經查證,
  依賴不確定存在的東西,壞掉的形式是「以為有人在跑」)。
- 補上原稿整份沒有的「載入契約」一節——那正是 leo 需求 3 的核心,也是 InkStoneCo#14 的根因。
- 補上 M4.6:release note 寫在 release 裡不寫 README(leo 2026-08-20 當場指正)。
- 補上 §3.4 總管收工義務:審核通過的當下就關票(leo 2026-08-20 指出上次 milestone 0% 的病)。

兩個裁決題已按判斷先做、理由寫在 DIVERGENCE §E,leo 可打回:
PR-only 只套 ISEP 不套全部 repo;舊的 duplicate 標籤封存不刪。
2026-08-20 13:02:28 +08:00

315 lines
17 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!-- 存檔:不要修改本檔。 -->
> 📦 **這是原稿存檔,不是現行規範。**
> 由 claude.ai 於 2026-08-20 寫成(v0.5.0 draft),leo 交給總管落地。
> **現行規範是同目錄的 `sdd-gitea-governance.md`v0.6.0**
> 兩者的逐條分歧與理由寫在 `DIVERGENCE-v0.5.0-to-v0.6.0.md`。
>
> 保留原稿的理由:它的物件模型與封路哲學是這套治理的骨架,
> 修訂版只動「與現場實況對不上」的部分。要追某條規則的來歷,看這裡。
---
# SDD × Gitea 治理規範
version: 0.5.0
status: draft(本文件自身的修改依 §9 走 issue)
scope: 適用於所有安裝本 plugin 的環境(地端 CC 與雲端薄殼)
distribution: 本規範隨治理 plugin 發佈,plugin repo 為唯一編輯點(§11)
---
## 0. 公理
1. **意圖真相在 SDD,狀態真相在 Gitea,知識真相在 Wiki。** 時態分工:SDD 未來式、Gitea 現在式、Wiki 過去式(§12)。禁止交叉寫入。
2. **Issue 是唯一任務介面。** 任何工作不經 issue 不得開始。issue = spec,PR = deliverable,release = 交付原子單位。
3. **封路優於守規。** 凡可結構性擋掉的違規路徑,不依賴代理或人的自律。
4. **兩軸正交。** Tracking issue 管 scope 軸,milestone 管 time 軸。
5. **治理本體只有一份。** 封裝於治理 plugin;地端與雲端皆為安裝目標,不是編輯目標(§11)。
6. **審核不是任務,是路徑。** 審核 = review PR 並 merge,為交付唯一必經動作(§3.0)。
7. **人是特殊 executor。** 人的兩種介入——審核者(`gate/human`)與執行者(`exec/human`)——分別建模;人執票走同一狀態機,派工通道為 Telegram(§6)。
---
## 1. 物件模型(五層 + 一橫切)
```
SDD 文件(docs/)
└─ Tracking issue(label: hub) ← scope 軸
└─ Leaf issue ← 最小工作單位
└─ PR(closes #n) ← deliverable
└─ Release tag ← 交付原子單位
Milestone ────────────────────────────── ← time 軸,橫切上樹
```
| 物件 | 職責 | 明確不做 |
|---|---|---|
| SDD 文件 | 意圖、範圍、非目標、驗收哲學、驗收腳本位置 | 不含 leaf task、不記進度 |
| Tracking issue | scope 聚合、討論容器、驗收閘 | 不掛 milestone、不直接對應 PR |
| Leaf issue | 一個 PR 的 spec(或一個人執動作,§6.2) | 不再拆子票(要拆=升格,§5.5) |
| Milestone | 一個可測試版本的 timebox | 不承載討論、不表達語意分組 |
| PR | 實作 + 測試,merge 時自動關 leaf | 不手動關票 |
| Release | milestone 關閉時打 tag | — |
---
## 2. 連結規則
- **R2.1** SDD 的 tasks/journey 段落只連 tracking issue,禁止連 leaf。
- **R2.2** 每張 leaf 必屬**恰好一個** tracking issue(task list 登記 + leaf 首行回鏈 `Parent: #n`)。
- **R2.3** 每張 leaf 最多屬一個 milestone。未排程 = 不掛(即 backlog)。
- **R2.4** Tracking issue 不掛 milestone。其子票可分屬多個 milestone。
- **R2.5** 順序關係一律用 Gitea 原生 dependency,禁止只寫文字。
---
## 3. 完成語意與票的狀態機
### 3.0 狀態機(每個轉移 = 一個可 hook 的 API 動作)
```
s/todo ──領票──▶ s/doing ──完成──▶ s/review ──總管 merge──▶ closed
(executor (開 PR + (closes #n
self-assign 轉 label) 自動關票)
+ 轉 label)
```
- **S3.0.1(領票)** Executor(subagent 或人)領任務 = self-assign + 轉 `s/doing`。禁止留言認領——留言不改變狀態。
- **S3.0.2(完成)** 宣告完成 = 開 PR(含 `closes #n`)+ 轉 `s/review`。**留言說做完不構成完成。**(人執票例外見 §6.2)
- **S3.0.3(審核)** 總管審核 = review PR 並 merge,merge 即自動關票。審核沒有其他形式,也沒有獨立審核票。
- **S3.0.4** 審核不通過:PR request changes,票退回 `s/doing`,續作。禁止關 PR 重開新票(保留審核軌跡)。
### 3.13.3 完成語意
- **D3.1** Leaf 關閉 = local_done。唯一觸發:PR merge 且含 `closes #n`(人執票例外 §6.2)。禁止手動關閉(例外見 §5、§6.2)。
- **D3.2** Tracking issue 關閉 = path_done:(1) 子票全關(必要);(2) SDD 驗收腳本通過(充分);(3) `gate/human` 已放行。
- **D3.3** 子票全關但驗收未過:tracking 保持開啟,開新 leaf 修復掛回。禁止「先關再說」。
---
## 4. Milestone 規則(= sprint = 可測試版本)
- **M4.1** 命名 `vX.Y`,必設 due date。
- **M4.2** Deliverable:所有掛入 leaf 關閉後,可從預設分支打出通過驗收腳本的版本。
- **M4.3** **Timebox 不可延長。** 到期:強制關閉 → 未完成 leaf 搬下一 milestone → 打 tag(即使 scope 縮水)。排程 job 執行。
- **M4.4** Milestone 關閉 = release tag,一對一。「已交付」唯一合法形式是 tag 存在;打 tag 前置 open issues = 0(E12)。
- **M4.5** Description 只寫版本目標一句 + tracking 連結。討論回 tracking issue。
---
## 5. Issue 關閉分類(taxonomy)
關閉必掛恰好一個 `close/*`:
| Label | 語意 | 關閉者 |
|---|---|---|
| `close/merged` | PR merge 自動關 | 系統 |
| `close/human-exec` | 人執票完成,人手動關(§6.2) | 人 |
| `close/duplicate` | 重複,指向舊票(新關舊留) | 人或代理 |
| `close/wontfix` | 討論後不做 | 人 |
| `close/stale` | 逾期無資訊 | 排程 job |
| `close/split` | 拆分後關(§5.5) | 人 |
| `close/transferred` | 屬別的 repo | 人或代理 |
- **C5.5(拆分)** (a) 升格 tracking(加 `hub`)或 (b) 關閉掛 `close/split`,子票掛原 parent。
- **C5.6** `close/wontfix` 只有人可執行。代理只能提議。
---
## 6. 人的兩種介入(gate/human 與 exec/human)
### 6.1 gate/human——人是審核者(overlay)
- **H6.1.1** `gate/human` + assignee = richblack:工作由代理完成,人只放行或否決。
- **H6.1.2** 代理不得關閉帶此標籤的 issue、不得 merge 帶此標籤的 PR(hook + Gitea 權限雙重擋)。
- **H6.1.3** 只有人可移除標籤;移除即放行。
- **H6.1.4** 必設節點(可增不可減):tracking issue 關閉前、`close/wontfix`、milestone 建立與 scope 圈選、治理 plugin 修改 PR、**部署至 prod 的 PR**。
### 6.2 exec/human——人是執行者(票的屬性)
- **H6.2.1** 當 deliverable 所需的「tool」只有人擁有(GUI-only 設定、實體權限開通、法定簽署),票掛 `exec/human` + assignee = richblack。人視為一個特殊 subagent,走 §3.0 同一狀態機。
- **H6.2.2** 人執票的 deliverable 是**環境狀態改變**,不是 PR。完成方式:人在票上留 `[decision] 已完成:做了什麼` → 人手動關票,系統自動掛 `close/human-exec`(此為 E3 唯一合法的手動關票路徑,hook 放行條件:label 含 `exec/human` 且操作者為人)。
- **H6.2.3** 驗證不靠自述:人執票通常是下游票的 dependency;關票解鎖後,接手代理執行時若設定未生效會 fail fast——下游失敗即自動 reopen 人執票並重新通知。有驗收腳本者,orchestrator 於關票後立即執行驗證。
- **H6.2.4** 代理判定「這件事我做不到、只有人能做」時:開 `exec/human` 票 + 設好 dependency + 觸發通知,然後**繼續做不被 block 的其他票**,不空轉等待。
### 6.3 Telegram 通知(人閘的開路配套)
- **H6.3.1** 觸發:`gate/human``exec/human` 被掛上且 assignee = richblack 時,hook 即時發 Telegram(走小六 bot 通道)。
- **H6.3.2** 訊息格式(BLUF,與 §10.2 同構):
```
🔔 #123 需要你|[gate] 或 [exec]
一句話:這張票要你做什麼(≤40 字)
動作:review PR #45 並 merge / 到 CF 後台開啟 X 權限
卡誰:此票 block 了 #124 #125
連結:https://git.uncle6.me/...
```
- **H6.3.3** 節流:同票同狀態只通知一次;24 小時未處理提醒一次;之後併入每日 digest(一則彙總所有 pending 人閘),不轟炸。
- **H6.3.4** E13 的 orchestrator 連續 block 升級、E12 的交付被擋,同走此通道。
- **H6.3.5** 通知是投影不是狀態:Telegram 訊息遺失不影響治理正確性,真相永遠在 Gitea 票上(單向依賴,同 §12.4)。
---
## 7. 討論路由(社群模式相容)
```
新 issue → 討論 →
├─ 可做,獨立 → 掛入 tracking,排 milestone → 走 §3
├─ 可做,有依賴 → 同上 + dependency(§2.5)
├─ 只有人能做 → 掛 exec/human + dependency + 通知(§6.2)
├─ 重複 → close/duplicate
├─ 不做 → close/wontfix(人閘)
├─ 太大 → 升格 hub 或拆分(§5.5)
└─ 走錯棚 → close/transferred
```
多票收斂:建 tracking issue(scope),不是直接建 milestone。當且僅當「這批票 = 恰好一個可出貨版本」才同時建 milestone,tracking 保留作討論與驗收容器。
---
## 8. 封路清單(結構性強制)
| # | 封什麼路 | 用什麼封 |
|---|---|---|
| E1 | 直接 push 預設分支 | branch protection: PR-only |
| E2 | PR 不關聯 issue | PR 模板必含 `closes #`,CI 缺漏即 fail |
| E3 | 手動關 leaf | hook 攔截;僅放行 `close/*` 例外與 §6.2 人執路徑(exec/human + 操作者為人) |
| E4 | 被 block 的票先關 | Gitea issue dependency 開啟 |
| E5 | Milestone 延期 | 排程 job:到期自動關 + 搬票 + 打 tag |
| E6 | 代理越過人閘 | PreToolUse hook + orchestrator token 無 code write 權限 |
| E7 | SDD 內出現 leaf 連結 | pre-commit lint |
| E8 | Tracking issue 掛 milestone | 排程 job 摘除並告警 |
| E9 | 留言不合格式或超長 | hook:首行不匹配 `^\[(decision|question|blocker|progress|proposal)\]` 或 > 600 字元 reject;同票同 session > 3 則 reject |
| E10 | 就地修改治理檔案 | 安裝目錄唯讀 + hook,導向 plugin repo 開 issue |
| E11 | 地端雲端版本漂移 | SessionStart hook 比對 manifest,不一致 fail-fast |
| E12 | 宣稱交付但票未關 | release tag / 關 milestone hook:open issues > 0 即 reject,列出未關票號,同步 Telegram |
| E13 | 審核被遺忘 | Orchestrator Stop hook:`s/review` 佇列非空即 block stop;連續 block 逾 N 次 → `gate/human` + Telegram 升級 |
| E14 | Subagent 空口宣稱完成 | SubagentStop hook:領票須處於 `s/review` 且掛含 `closes #n` 的 PR,否則回報「未達交付態」 |
| E15 | 代理硬做只有人能做的事 | 對 GUI-only / 憑證外資源的操作路徑,代理端無對應 tool 或 token;唯一出口是開 `exec/human` 票(§6.2.4) |
| E16 | 標籤漂移(repo 標籤與規範不符) | 排程 job 走 Gitea labels API,依 plugin `labels.yaml` 校正所有受治理 repo:缺的補、改的還原、多的告警;不依賴模板檔與重啟(§11.4) |
---
## 9. 本規範的迭代
- 存於治理 plugin repo `docs/`;各環境為唯讀安裝副本。
- 修改:plugin repo 開 leaf(掛 governance tracking)→ PR → `gate/human` → merge → release → 各端升級。
- 版本:規則增刪 = minor,措辭 = patch,公理 = major。**plugin 版本 = 規範版本。**
- 每次 milestone 回顧:規範有無被繞過?有 → 補 §8,不加「請遵守」。
---
## 10. 留言規範
### 10.1 OP 唯一狀態原則
- OP 是票的唯一狀態容器,持續編輯;留言是 append-only 稽核 log,只記 delta。了解一張票只讀 OP。
- 討論收斂即寫回 OP,留言留 `[decision] 已更新 OP:改了 X,因為 Y`
### 10.2 留言格式(BLUF + 類型標籤,全文 ≤ 600 字元)
```
[類型] 一句話結論(≤40 字)
理由:
- (最多 3 個 bullet,每個 ≤ 1 行)
下一步: (一行,或「無」)
詳細: (連結至 PR / commit / wiki,禁止貼內文)
```
類型枚舉:`decision` `question` `blocker` `progress` `proposal`
能用 OP task list 打勾表達的進度不留言;重大 `proposal` 加掛 `gate/human`
### 10.3 推理軌跡出口
推理、嘗試、失敗分析走 wiki-capture 進 Wiki/KBDB,留言以 `詳細:` 指向。**推理進 wiki,結論進留言,留言只帶指標。**
---
## 11. 治理 Plugin(單點分發與同步)
### 11.1 結構
```
governance-plugin/
├── docs/sdd-gitea-governance.md
├── labels.yaml # 標籤唯一真相(§11.4)
├── hooks/ # E1E16
├── templates/ # issue / PR / 留言 / Telegram 通知模板
├── jobs/ # E5 / E8 / E16 / stale / digest
├── manifest.json # 版本 + checksum + shell-safe 清單
└── install.sh
```
### 11.2 分發規則
- **P11.2.1** 地端與雲端安裝**同一個 release**;來源只有 plugin repo release tag。
- **P11.2.2** 治理修改只發生在 plugin repo;執行環境發現需調整 → 去 plugin repo 開 issue(E10)。
- **P11.2.3** Session 啟動比對 manifest(E11);不一致 fail-fast,不降級執行。
- **P11.2.4** 升級是原子動作:整包替換,禁止 cherry-pick。
- **P11.2.5** 薄殼只裝 manifest 標記 `shell-safe` 的子集;薄殼不自行決定。
### 11.3 與既有 plugin 收斂
治理規則集中本 plugin;各專案 dispatch/harness hook 一律 import 本 plugin,不得複製(複製即 fork,fork 即漂移)。
### 11.4 標籤分發(labels.yaml)
- **P11.4.1(唯一真相)** 全部標籤定義(名稱、顏色、描述、exclusive)只存在於 plugin repo 的 `labels.yaml`。本規範附錄與 Gitea 上所見皆為投影;修改標籤 = 修改 labels.yaml,走 §9 流程。
- **P11.4.2(雙通道分發)** 同一份 labels.yaml 走兩條通道:
1. **模板通道(便利,弱)**:install/升級時部署至 Gitea 伺服器 `$GITEA_CUSTOM/options/label/governance.yaml`,供建新 repo 時 GUI 一鍵播種。**此通道生效需重啟 Gitea**,且僅為一次性播種,不校正既有 repo。
2. **API 通道(真相,強)**:排程 job(E16)走 labels API 掃所有受治理 repo,依 labels.yaml 校正——缺的補、改的還原、多出的非規範標籤留言告警(不自動刪,避免誤殺專案自用標籤)。**不需重啟,對既有 repo 立即生效。**
- **P11.4.3(依賴方向)** 正確性只依賴 API 通道。忘記重啟的後果僅是「建新 repo 的 GUI 下拉是舊版」,而新 repo 納入治理後第一次 E16 掃描即被校正——模板通道壞掉不影響治理正確性(同 §12.4 單向依賴)。
- **P11.4.4(升級程序)** plugin release 若含 labels.yaml 變更,install.sh 依序執行:(1) 部署模板檔;(2) 重啟 Gitea(`systemctl restart gitea`,寫在腳本裡,不靠人記得);(3) 立即觸發一次 E16 全量 sync;(4) 驗證:抽查一個 repo 的標籤集與 labels.yaml 一致才回報升級成功。
- **P11.4.5(平台級不變量)** `s/*``close/*` 一律 `exclusive: true`:同 scope 同票至多一個標籤,由 Gitea 平台保證(轉移時自動摘除舊標籤)。狀態唯一性與關閉分類唯一性因此無需 hook 維護——非法狀態不可表示。
---
## 12. 書寫路由(SDD × Gitea × Wiki)
### 12.1 時態原則
| 載體 | 時態 | 回答的問題 | 變動頻率 | 寫入者 |
|---|---|---|---|---|
| SDD | 未來式 | 要做什麼、為什麼、怎樣算完成 | 低(人閘審) | 人(代理僅提案) |
| Gitea | 現在式 | 誰在做、做到哪、卡在哪、順序 | 高(狀態機) | 人與代理 |
| Wiki | 過去式 | 怎麼想、試過什麼、學到什麼 | append-only | 主要是代理 |
### 12.2 路由判準(寫之前問一句:這段內容改變的是什麼?)
- 「要做什麼」(範圍、驗收、非目標)→ SDD,必經 issue + 人閘(改意圖 = 改合約)
- 「現在狀態」(認領、進度、卡點、定案)→ Gitea(OP 或合規留言)
- 「我們知道什麼」(推理、失敗、可復用教訓)→ Wiki
### 12.3 典型錯置與矯正
| 錯置 | 矯正 |
|---|---|
| SDD 長出 task 清單、進度勾選 | 移至 Gitea;E7 攔截 |
| Issue 留言寫滿推理長文 | 移至 Wiki 留指標;E9 攔截 |
| Wiki 記錄「目前進度」 | 刪除;進度只存在於 Gitea。Wiki 引用票寫「當時」 |
| Issue OP 修改驗收標準 | 退回:先開 SDD 修改 issue(人閘),定案後 OP 才同步 |
| 代理直接編輯 SDD | SDD 目錄對代理唯讀,提案走 issue |
### 12.4 連結方向(單向依賴)
SDD → 只連 tracking(R2.1)。Gitea → 可連 SDD 錨點與 wiki。Wiki → 可連票號與 commit,皆為歷史快照語意。Telegram 通知 → 純投影(H6.3.5)。**Wiki 壞不影響 Gitea,Gitea 壞不影響 SDD,通知丟不影響一切。**
---
## 附:Label 全集(快照;唯一真相為 plugin `labels.yaml`,§11.4)
```
hub # tracking issue 標記
s/todo s/doing s/review # 狀態機三態(Stage,§3.0),exclusive;closed 為系統態
gate/human # 人是審核者(§6.1)
exec/human # 人是執行者(§6.2)
close/* # 七種關閉分類(§5),exclusive
type/* # type/bug type/feature type/governance
```
本附錄不逐項列 close/*,以免與 labels.yaml 形成第二份清單而漂移。