Files
ISEP/docs/governance/sdd-gitea-governance.md
T
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

407 lines
24 KiB
Markdown
Raw 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.
# SDD × Gitea 治理規範
```
version: 0.6.0
status: 現行(本檔的修改依 §9 走 issue)
scope: 所有安裝 ISEP 的環境(本機 CC 與雲端 CC)
distribution: 隨 ISEP 發佈,ISEP repo 是唯一編輯點(§11
lineage: v0.5.0 draft by claude.ai(存檔 _draft-claude-ai-v0.5.0.md
→ v0.6.0 由總管對照現場實況修訂,逐條分歧見 DIVERGENCE-v0.5.0-to-v0.6.0.md
```
---
## 0. 公理
1. **意圖真相在 SDD,狀態真相在 Gitea,知識真相在 Wiki。** 時態分工:SDD 未來式、Gitea 現在式、Wiki 過去式(§12)。禁止交叉寫入。
2. **Issue 是唯一任務介面。** 任何工作不經 issue 不得開始。issue specPR deliverablerelease 交付原子單位。
3. **封路優於守規。** 凡可結構性擋掉的違規路徑,不依賴代理或人的自律。
🔴 **封的是「動作」,不是「措辭」**leo 2026-08-17):自然語言的變體無限,blacklist 追不完;動作有限且可枚舉。
4. **兩軸正交。** Tracking issue 管 scope 軸,milestone 管 time 軸。
5. **治理本體只有一份,而且沒有子集。** 封裝於 ISEP;本機與雲端都是**安裝目標**,不是編輯目標(§11)。
🔴 **不存在「薄殼只裝一部分」這種東西**——那正是 `InkStoneCo#57` 的成因。
6. **審核不是任務,是路徑。** 審核 review PR 並 merge,是交付的唯一必經動作(§3.0)。
7. **人是特殊 executor。** 人的兩種介入——審核者(`Human`)與執行者(`human/exec`)——分別建模,走同一狀態機(§6)。
---
## 1. 物件模型(五層 + 一橫切)
```
SDD 文件(docs/
└─ Tracking issuelabel: hub ← scope 軸
└─ Leaf issue ← 最小工作單位
└─ PRcloses #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 | 不在 README 裡宣稱版本(§4.6 |
---
## 2. 連結規則
- **R2.1** SDD 的 tasksjourney 段落只連 tracking issue,禁止連 leaf。
- **R2.2** 每張 leaf 必屬**恰好一個** tracking issuetracking 的 task list 登記 leaf 首行回鏈 `Parent: #n`)。
- **R2.3** 每張 leaf 最多屬一個 milestone。未排程 不掛(即 backlog)。
- **R2.4** Tracking issue 不掛 milestone。其子票可分屬多個 milestone。
- **R2.5** 順序關係一律用 Gitea 原生 dependency`/issues/{n}/dependencies`,已驗證可用),禁止只寫文字。
- **R2.6** 跨 repo 的票**不搬**——Gitea 沒有 issue transfer API(已驗證)。改用互鏈:在收斂方開 hub,OP 內以 `owner/repo#N` 全稱指回。
🔴 票號一律寫全稱,裸號跨 repo 會撞號。
---
## 3. 完成語意與票的狀態機
### 3.0 狀態機
```
s/triage ──驗傷通過──▶ s/backlog ──排進 milestone──▶ s/todo
│ 領票(self-assign
s/doing ──開 PRcloses #n)──▶ s/review
▲ │ 總管 merge
│ ▼
s/pending closed
(卡外部/等依賴) │ 若這一版要 leo 實驗
s/stage
```
七個態,全部 `exclusive: true`(Gitea 平台保證同票至多一個,非法狀態不可表示):
| 態 | 意思 | 誰轉進來 |
|---|---|---|
| `s/triage` | 新進來的,還沒驗傷 | 任何人開票 |
| `s/backlog` | 確定要做,還沒排 sprint | 驗傷者 |
| `s/todo` | 已排進 milestone,等人領 | 總管 |
| `s/doing` | 有人在做(已 self-assign | executor 自己 |
| `s/review` | PR 已開,等總管 merge | executor 自己 |
| `s/stage` | 已部署 stage,等 leo 實際驗收 | 總管 |
| `s/pending` | 卡住——等外部/等依賴 | 任何人,但要寫明卡什麼 |
- **S3.0.1(領票)** 領任務 self-assign `s/doing`。**留言認領不算**——留言不改變狀態。
- **S3.0.2(完成)** 宣告完成 = 開 PR(含 `closes #n`)+ 轉 `s/review`。**留言說做完不構成完成**(人執票例外見 §6.2)。
- **S3.0.3(審核)** 總管審核 review PR 並 mergemerge 即自動關票。沒有獨立的審核票。
- **S3.0.4(退回)** 審核不通過:PR request changes,票退回 `s/doing`,續作。**禁止關 PR 重開新票**(會弄丟審核軌跡)。
- **S3.0.5`s/review` vs `s/stage`)** 兩者是不同的等待,不可互相取代:
`s/review` = 程式碼還沒進 main,等**總管**;`s/stage` 已上測試環境,等 **leo 打開來看**
### 3.13.3 完成語意
- **D3.1** Leaf 關閉 local_done。唯一觸發:PR merge 且含 `closes #n`(人執票例外 §6.2)。禁止手動關閉。
- **D3.2** Tracking issue 關閉 path_done(1) 子票全關【必要】;(2) 驗收腳本通過【充分】;(3) `Human` 已放行。
- **D3.3** 子票全關但驗收未過:tracking 保持開啟,開新 leaf 修復並掛回。**禁止「先關再說」。**
### 3.4 🔴 總管的收工義務(本規範最常被違反的一條)
> leo 2026-08-20 原話:「先前你建立 milestone,但當 subagent 完成工作,你審核後卻沒有關票,
> 導致 milestone 0% 完工,等說了才去關票,**這些都是大問題**。」
- **審核通過的當下就要關票,不是收工前補、不是被提醒才補。**
- 判準:**milestone 的百分比就是 leo 唯一看得到的進度**。票沒關 = 對他而言那件事沒發生。
- 「我審完了但還沒關」不是一個合法狀態——審完 = merge = 票自動關;沒關就表示你沒真的審完。
---
## 4. Milestone 規則(= sprint 可測試版本)
- **M4.1** 命名 `vX.Y`,必設 due date。
- **M4.2** Deliverable **一個可測的新版本號**。所有掛入 leaf 關閉後,可從預設分支打出通過驗收的版本。
- **M4.3** **Timebox 到期不自動關、不自動打 tag。** 到期強制做一次降 scope 對帳(未完成 leaf 搬下一 milestone)並通知 leo。
🔴 自動打 tag 會製造假交付——tag 永遠只在「驗過了」之後發生。
- **M4.4** Milestone 關閉 release tag,一對一。「已交付」唯一合法形式是 **tag 存在且裝得起來**;打 tag 前置 open issues 0(§8 E12)。
- **M4.5** Description 只寫版本目標一句 tracking 連結。討論回 tracking issue。
- **M4.6** 🔴 **release note 寫在 Gitea Releases 裡,不寫在 README。**leo 2026-08-20:「release 不是寫在 readme,要放在 release 裡」)
README 不得自行宣稱版本號——那會產生第二份會漂移的版本真相。
---
## 5. Issue 關閉分類
關閉必掛恰好一個 `close/*``exclusive: true`):
| Label | 語意 | 關閉者 |
|---|---|---|
| `close/merged` | PR merge 自動關(正常路徑) | 系統 |
| `close/human-exec` | 人執票完成,人手動關(§6.2) | 人 |
| `close/duplicate` | 重複,指向舊票(關新留舊) | 人或代理 |
| `close/wontfix` | 討論後決定不做 | **只有 leo** |
| `close/stale` | 逾期無資訊 | job |
| `close/split` | 拆分後關(§5.5) | 人或代理 |
| `close/transferred` | 屬別的 repo,已在那邊重開 | 人或代理 |
- **C5.5(拆分)** (a) 升格 tracking(加 `hub`)或 (b) 關閉掛 `close/split`,子票掛原 parent。
- **C5.6** `close/wontfix` 只有人可執行。代理只能提議。
- **C5.7** 既有的 `duplicate` 標籤**封存不刪**(刪除會把它從所有歷史票上摘掉)。
---
## 6. 人的兩種介入
### 6.1 `Human`——人是審核者(正交 overlay)
- **H6.1.1** `Human` assignee = Leo:工作由代理完成,人只放行或否決。
- **H6.1.2** 🔴 **`Human` 不是流程狀態,是正交維度**(leo 2026-08-17)——可疊在任何 `s/*` 上,不與 `s/*` 二選一。
- **H6.1.3** 代理不得關閉帶此標籤的 issue、不得 merge 帶此標籤的 PR。
- **H6.1.4** 只有人可移除標籤;移除即放行。
- **H6.1.5** 必設節點(可增不可減):tracking issue 關閉前、`close/wontfix`、milestone 建立與 scope 圈選、**ISEP 自身的修改 PR**、**部署至 prod 的 PR**。
- **H6.1.6** 🔴 **交棒給 leo = 三個機械動作,缺一件等於沒交棒**leo 2026-08-17):
① 總管自己先在 stage 驗過 → ② 把票**指派給 Leo** → ③ 掛 `Human`
在對話裡說「你可以驗了」不算——那句話會捲走,assignee 與標籤不會。
順序不可顛倒:沒驗過就指派 = 把第一次驗證推給他。
### 6.2 `human/exec`——人是執行者(票的屬性)
- **H6.2.1** 當 deliverable 所需的能力只有人擁有(GUI-only 設定、實體權限開通、法定簽署、terminal consent),
票掛 `human/exec` assignee Leo。人視為特殊 subagent,走 §3.0 同一狀態機。
- **H6.2.2** 人執票的 deliverable 是**環境狀態改變**,不是 PR。完成方式:人在票上留 `[decision] 已完成:做了什麼` → 人手動關票 → 掛 `close/human-exec`
這是唯一合法的手動關票路徑。
- **H6.2.3** 驗證不靠自述:人執票通常是下游票的 dependency;關票解鎖後,接手代理若發現設定沒生效即 fail fast,**下游失敗自動 reopen 人執票**。
- **H6.2.4** 🔴 代理判定「這件事只有人能做」時:開 `human/exec` 設好 dependency + 通知,然後**繼續做其他不被 block 的票**,不空轉等待。
### 6.3 Telegram 通知(人閘的開路配套)
- **H6.3.1** 觸發:`Human``human/exec` 被掛上且 assignee Leo 時,即時發 Telegram。
通道與帳號**不寫死在本檔**,真相源是 `wiki/agent-memory.md` 的通知通道段。
- **H6.3.2** 訊息格式(白話鐵律:標題一眼懂、代號必附一句人話):
```
🔔 #123 需要你|[放行] 或 [只有你能做]
一句話:這張票要你做什麼(≤40 字,不准只寫代號)
動作:review PR #45 並 merge 到 CF 後台開啟 X 權限
卡誰:此票 block 了 #124 #125
連結:https://git.uncle6.me/...
```
- **H6.3.3** 節流:同票同狀態只通知一次;24 小時未處理提醒一次;之後併入每日 digest。
🔴 但「等了幾天」要標出來——對 leo 重複=服務,不催這件事就不會發生。
- **H6.3.4** 通知是**投影不是狀態**:訊息遺失不影響治理正確性,真相永遠在 Gitea 票上。
---
## 7. 討論路由
```
新 issues/triage)→ 驗傷 →
├─ 可做,獨立 → 掛入 tracking,排 milestone → 走 §3
├─ 可做,有依賴 → 同上 dependencyR2.5
├─ 只有人能做 → human/exec dependency 通知(§6.2
├─ 重複 → close/duplicate
├─ 不做 → close/wontfix(只有 leo
├─ 太大 → 升格 hub 或拆分(C5.5)
└─ 走錯棚 → 在正確 repo 重開,本張 close/transferredR2.6:不能搬)
```
多票收斂:建 tracking issuescope),**不是直接建 milestone**。
當且僅當「這批票 = 恰好一個可出貨版本」才同時建 milestone。
🔴 **開工第一個動作是建里程碑並拉既有 issue,不是開新票**leo 2026-08-19)。
里程碑**一張新任務都不准增**;撈不到對應的票 ⇒ 那才是真缺口 ⇒ 去票池補一張,不是在里程碑裡編。
🔴 **票名一律 User Story**`身為<誰>,我要<什麼>,我才<為什麼>`
不准自創分類前綴(`【版本】``👤 裁決題:` 都被廢除過)。
---
## 8. 封路清單(每條標明現況,已有的不重造)
| # | 封什麼路 | 用什麼封 | 現況 |
|---|---|---|---|
| E1 | 直接 push 預設分支 | branch protectionPR-only | ◐ 現有 `main-and-prod-push-guard.sh` 語意相反(擋 subagent、放行總管)。**本版只對 ISEP 開 PR-only**,見 §8.1 |
| E2 | PR 不關聯 issue | PR 模板必含 `closes #`,缺漏即 fail | ❌ 待建 |
| E3 | 手動關 leaf | hook 攔截;只放行 `close/*` 與 §6.2 人執路徑 | ❌ 待建 |
| E4 | 被 block 的票先關 | Gitea issue dependency | ✅ 平台原生,已驗證可用 |
| E5 | Milestone 悄悄過期 | job:到期做降 scope 對帳 + 通知(**不自動關、不自動打 tag**) | ❌ 待建(先做成手動腳本,見 §8.2) |
| E6 | 代理越過人閘 | PreToolUse hook | ◐ 現有 `irreversible-dispatch-guard.sh``prod-write-guard.sh` 覆蓋一部分 |
| E7 | SDD 內出現 leaf 連結 | pre-commit lint | ❌ 待建 |
| E8 | Tracking issue 掛 milestone | job 摘除並告警 | ❌ 待建 |
| E9 | 留言變成推理長文 | hook:超長**不 reject**,要求移去 wiki 再留指標 | ❌ 待建(放寬版,見 §8.3) |
| E10 | 就地修改治理檔案 | 安裝目錄唯讀 + hook,導向 ISEP 開 issue | ❌ 待建 |
| E11 | 本機雲端版本漂移 | SessionStart hook 比對版本,不一致 fail-fast | ◐ 現有 `skill-deploy-drift-guard.sh` 管的是 skill 不是 plugin 版本 |
| E12 | 宣稱交付但沒有 release | 版本三處一致閘:`plugin.json` tag release 存在;且 milestone open issues 0 不准打 tag | ◐ 現有 `delivery-police.sh``claim-verify-police.sh` 部分覆蓋 |
| E13 | 審核被遺忘 | Stop hook**我自己開的** `s/review` 存在且**這回合完全沒碰它** → 擋一次 | ◐ 現有 `empty-handed-stop-guard.sh` 判準不同,兩者要合併不要疊加 |
| E14 | Subagent 空口宣稱完成 | SubagentStop hook | ✅ **已有** `subagent-claim-worksheet.sh` `empty-handed-stop-guard.sh` |
| E15 | 代理硬做只有人能做的事 | 代理端無對應 tool 或 token;唯一出口是開 `human/exec` 票 | ◐ 部分(credential 機制已擋一部分,D36 |
| E16 | 標籤漂移 | 走 Gitea labels API 依 `labels.yaml` 校正:缺的補、改的還原、多的**只告警不刪** | ❌ 待建(`ISEP#4` |
### 8.1 E1 的適用範圍(裁決記錄)
**只有 ISEP 走 PR-only;其他 repo 維持現行「總管推 main 自己裁」。**
- 理由:ISEP 壞掉 **所有 session 一起壞**,值得多一道摩擦;其他 repo 壞掉只影響自己。
- 一刀切到 14 個 repo 會在 leo 最忙的時候把整條線卡在「等總管開 PR」。
- 這條命中四題公式的「跨專案結構」⇒ 已記為裁決題(`DIVERGENCE` §E1),leo 可打回。
### 8.2 所有 job 第一版都不依賴 Gitea Actions runner
- 做成 `scripts/` 底下可手動跑、也可由 SessionStart hook 順手跑的東西。
- 理由:**這台 Gitea 有沒有掛 runner,本規範撰寫時未經查證。**
依賴一個不確定存在的東西,壞掉的形式是「以為有人在跑」——比「沒人跑」貴得多。
- 確認有 runner 後才升級成排程,升級走 §9。
### 8.3 E9 為什麼放寬(不是偷懶)
leo 2026-08-17 實測:文字層的閘那天 **8 次誤攔、0 次正確攔截**,且方向穩定——
**紅線寫得越細,命中關鍵字的機率越高 ⇒ 那些閘在懲罰謹慎。**
所以 E9 擋的是「長內容放錯地方」這個**動作**,處置是**導引**(移去 wiki 留指標),不是 reject。
---
## 9. 本規範的迭代
- 存於 ISEP `docs/governance/`;各環境為唯讀安裝副本。
- 修改路徑:ISEP 開 leaf(掛 governance tracking)→ PR → `Human` 放行 → merge → release → 各端升級。
- 版本:規則增刪 = minor,措辭 = patch,公理 major。**ISEP plugin 版本 本規範版本。**
- 每次 milestone 回顧問一句:**規範有沒有被繞過?** 有 → 補 §8 的封路,**不加一句「請遵守」**。
---
## 10. 留言規範
### 10.1 OP 唯一狀態原則
- **OP 是票的唯一狀態容器**,持續編輯;留言是 append-only 的稽核 log,只記 delta。
- 了解一張票只讀 OP。討論收斂即寫回 OP,留言留 `[decision] 已更新 OP:改了 X,因為 Y`
### 10.2 留言格式(BLUF 類型標籤)
```
[類型] 一句話結論(≤40 字)
理由:
- (最多 3 個 bullet,每個 ≤1 行)
下一步:(一行,或「無」)
詳細:(連結至 PR/commit/wiki,禁止貼內文)
```
類型:`decision` `question` `blocker` `progress` `proposal`
能用 OP 的 task list 打勾表達的進度**不留言**;重大 `proposal` 加掛 `Human`
### 10.3 推理軌跡出口
推理、嘗試、失敗分析走 wiki-capture 進 WikiKBDB,留言以 `詳細:` 指向。
**推理進 wiki,結論進留言,留言只帶指標。**
---
## 11. ISEP(單點分發與同步)
### 11.1 實際結構(2026-08-20 實況,不是理想圖)
```
ISEP/
├── .claude-plugin/
│ ├── plugin.json # 版本號真相源之一(§8 E12 要三處一致)
│ └── marketplace.json # host 發現這個 plugin 的入口
├── docs/governance/ # 本規範 + 原稿存檔 + 分歧說明
├── labels.yaml # 標籤唯一真相(§11.4)
├── hooks/ # 41 支 hooks.json51 條註冊)
├── commands/ # 7 支 slash command
├── skills/ # 2 支
├── scripts/ # 23 支
└── system-dev/wiki/ # ISEP 自己的知識庫(只記 ISEP 的事)
```
🧹 **已知待清理**`scripts/install.sh` 實際是 **system-dev-template 的安裝器**(在裝 wikiSDD),
搬家時混進來的,與 plugin 無關。
### 11.2 分發規則
- **P11.2.1** 本機與雲端安裝**同一個 release**;來源只有 ISEP 的 release tag。
- **P11.2.2** 治理修改只發生在 ISEP;執行環境發現需調整 → 回 ISEP 開 issueE10)。
- **P11.2.3** Session 啟動比對版本(E11);不一致 fail-fast,不降級執行。
- **P11.2.4** 升級是原子動作:整包替換,禁止 cherry-pick。
- **P11.2.5** 🔴 **沒有子集。** 本機與雲端裝的是**逐位元組相同**的一份。
(原稿的「薄殼只裝 shell-safe 子集」已刪除——那條是舊薄殼模型的殘留,
正是 `InkStoneCo#57`「薄殼比真身少 7 支閘」的成因本身。)
### 11.3 載入契約(原稿缺這節,而這是最容易默默失敗的一格)
Claude Code **只在 session 啟動當下**讀一次 cwd 的設定。因此:
- **L11.3.1** 雲端 session 的 cwd 是 GitHub 上的啟動 repoISEP 必須在**那個時刻**就被 host 認得。
- **L11.3.2** 「事後 clone 進來」對 hook 可行(hook 是每次工具呼叫才解析路徑),
**commandskill 不可行**(它們啟動時就被掃描)——這是 `InkStoneCo#14` 的根因。
- **L11.3.3** ISEP 是 **private** repo,任何載入路徑都必須先解決憑證。
憑證只准取名字(D36),**不得寫進任何檔案、commit 或 issue**。
- **L11.3.4** 驗收標準:能貼出**雲端那邊實際載到的清單**,逐條對上 ISEP 的註冊條數。
「我推上去了」不是驗收。
### 11.4 標籤分發(labels.yaml
- **P11.4.1(唯一真相)** 全部標籤定義(名稱、顏色、描述、exclusive)只存在於 ISEP 的 `labels.yaml`
Gitea 上所見皆為投影;改標籤 = 改 `labels.yaml`,走 §9。
- **P11.4.2(分發通道)** **API 通道是唯一依賴**:走 labels API 掃所有受治理 repo 校正。
Gitea 伺服器端的模板檔(建新 repo 時 GUI 播種)是**可選的便利品**,
獨立腳本、不掛在安裝流程上——它需要重啟 Gitea,而重啟的成本與風險不該由安裝觸發。
- **P11.4.3(依賴方向)** 正確性只依賴 API 通道。模板通道壞掉的後果僅是「建新 repo 的下拉是舊版」,
而新 repo 納管後第一次 sync 即被校正。
- **P11.4.4(不刪原則)** 🔴 **同步永不刪除標籤**——刪除會把它從所有歷史票上摘掉,不可逆。
非規範標籤只列出告警。
- **P11.4.5(平台級不變量)** `s/*``close/*``p/*``type/*` 一律 `exclusive: true`
Gitea 1.26.4 支援,已驗證):同 scope 同票至多一個,由平台保證——**非法狀態不可表示**,無需 hook 維護。
`Human``human/exec``hub` 是正交維度,**不 exclusive**。
---
## 12. 書寫路由(SDD × Gitea × Wiki
### 12.1 時態原則
| 載體 | 時態 | 回答的問題 | 變動頻率 | 誰寫 |
|---|---|---|---|---|
| SDD | 未來式 | 要做什麼、為什麼、怎樣算完成 | 低 | 代理可寫,**範圍/驗收/非目標的變更必經人閘** |
| Gitea | 現在式 | 誰在做、做到哪、卡在哪、順序 | 高 | 人與代理 |
| Wiki | 過去式 | 怎麼想、試過什麼、學到什麼 | append-only | 主要是代理 |
(原稿寫「SDD 寫入者是人、代理僅提案」——與現況相反,照字面走第一天就違規。
管的應該是**哪些欄位需要 leo 點頭**,不是誰握筆。)
### 12.2 路由判準(寫之前問一句:這段內容改變的是什麼?)
- 「要做什麼」(範圍、驗收、非目標)→ SDD,必經 issue + 人閘(改意圖 = 改合約)
- 「現在狀態」(認領、進度、卡點、定案)→ Gitea(OP 或合規留言)
- 「我們知道什麼」(推理、失敗、可復用教訓)→ Wiki
### 12.3 典型錯置與矯正
| 錯置 | 矯正 |
|---|---|
| SDD 長出 task 清單、進度勾選 | 移至 Gitea;E7 攔截 |
| Issue 留言寫滿推理長文 | 移至 Wiki 留指標;E9 導引 |
| Wiki 記錄「目前進度」 | 刪除;進度只存在於 Gitea。Wiki 引用票時寫「當時」 |
| Issue OP 修改驗收標準 | 退回:先開 SDD 修改 issue(人閘),定案後 OP 才同步 |
| **README 宣稱版本號** | 刪除;版本只存在於 releaseM4.6)。2026-08-20 實犯 |
### 12.4 連結方向(單向依賴)
SDD → 只連 trackingR2.1)。Gitea → 可連 SDD 錨點與 wiki。Wiki → 可連票號與 commit(歷史快照語意)。
Telegram → 純投影。**Wiki 壞不影響 GiteaGitea 壞不影響 SDD,通知丟不影響一切。**
---
## 附:Label 全集(快照;唯一真相為 `labels.yaml`
```
狀態機(exclusive s/triage s/backlog s/todo s/doing s/review s/stage s/pending
關閉分類(exclusive close/merged close/human-exec close/duplicate close/wontfix
close/stale close/split close/transferred
人(正交,不 exclusive Human ← 人是審核者
human/exec ← 人是執行者
優先(exclusive p/high p/low
種類(exclusive type/bug type/feature type/governance type/chore
結構(正交) hub ← tracking issue 標記
封存不刪 duplicate ← 由 close/duplicate 取代,保留在歷史票上
```