---
name: driving-work-to-done
description: |
  把一件工作從「有人說了一句話」帶到「judged 過的交付」：先判斷要不要立案，再決定現在
  該在 refinement / engineering / verify-ac 哪一站、什麼時候換站，載入說明「這類工作怎麼算
  done」的知識，然後一路推進到收斂或撞上四種已宣告的停點之一。任何會改變程式碼或行為的
  請求都從這裡進，使用者不需要知道這個名字。唯讀的查詢與說明不走這裡。

  有人帶著一件要做的事出現時的第一站，不論他有沒有說出任何指令名稱。例如
  「幫我做 X」「這個壞了要修」「想重構 Y」「繼續」「接著推」。

  也用於：不知道現在在哪、不知道下一步是什麼、手上有多張單不知道先做哪一張。

  不用於：唯讀的查詢與說明（「這支腳本在幹嘛」「查一下 X」）——那些沒有「怎麼算成功」
  要簽，直接回答。
metadata:
  version: 1.0.0
  requires:
    - skill: refinement
      why: 立案之後簽 assertion 那一站；也是開種子單的地方（本支散文指名 open-seed-issue.sh）
    - skill: engineering
      why: 兩個關卡之間那一站；本支只說「去那裡」，不說怎麼做
    - skill: verify-ac
      why: 判定達成那一站；本支明文不做判定
scope: universal
---

# driving-work-to-done — 一件工作、一個入口、一個下一步

三支 skill 各做一站的事：`refinement` 簽下成功的定義，`engineering` 施工，`verify-ac`
判定。**它們都不決定下一步是什麼**——那寫在這裡，只寫在這裡。

一份工作有兩種成功條件，它們住在不同地方：

- **這張單獨有的**（acceptance criteria）→ 進 `refinement` 凍結的 fence。
- **這一類工作共用的**（definition of done）→ 由領域知識帶進來，見〈載入領域知識〉。

把共用的那份寫進每一張單的 fence，等於每次都重簽同樣幾行不承載新資訊的東西。

## 一、有工作進來：要不要立案

判準只有一條：**有沒有「怎麼算成功」需要人簽字。**

| 這件事 | 立案？ |
|---|---|
| 查一下、說明一段程式、跑個既有測試 | 否。什麼都沒改，沒有要簽的東西 |
| 會改到程式碼或行為——不論多小 | **是** |
| 不確定 | **是**。立案的成本遠低於做完才發現目標不對 |

**只讀的問題不走這條**，其餘都走。以前這裡有一格是「改 typo、調一個顯然的常數 → 否，
成功的定義不會有爭議」，拆掉了：那一格的判準是「這件事夠小」，而那是每次都由當事人自己
判、每次都會判得更寬的東西。

**把判斷與依據說出來**，一句話就夠，讓人能當場推翻。不立案的到此為止，直接把事做完。

### 手上正在做別的事，但長出了一個不能消失的東西

開發途中會問出、查出、撞出只有當下知道的東西。停下來簽一張正式的單太貴——assertion 此刻也
簽不出來，因為怎麼算成功還沒想清楚。丟著又會消失：一個修正留在一個到不了別人手上的
地方，跟沒有那個修正是一樣的（2026-08-07 真的發生過，同一個 bug 因此咬了兩版）。

所以有第三條路：**開一張種子單，然後回去做你原本在做的事。**

開單那一刻要回答兩件事：**這是哪一種單**，以及**這件事有沒有人已經記過了**。

- **種類自己宣告**，開單那條路不從名字或內容推。舉發實作途中撞到的問題，跟開發一個新
  功能，問得出答案的東西不一樣——撞到的人當下就知道自己是誰、剛剛在讀哪個檔，而想加
  新功能的人沒有「撞到」這件事，那兩格硬填會填出一個編的。
- **舉發那一種開之前會看到撞到了哪幾張**，並且要對每一張寫下一句判斷。**判斷的內容不
  決定開不開得成單**——說「都不是同一件」照樣開得出來。擋人的只有「沒有回答問題」。

```bash
bash .claude/skills/refinement/scripts/open-seed-issue.sh \
  --issues issues --namespace <命名空間> --slug <名字> --kind report \
  --who <誰、在做什麼工作時撞到的> --where <撞到的檔案> \
  --what <做什麼> --when <什麼時候要> --why <想解決什麼> --how <拿什麼測> \
  --note '<前因後果>' [--vs <單號>=<判斷>]...
```

新功能那一種是 `--kind feature`，不問 `--who` 與 `--where`，也不查重。跑 `--help` 看
兩種各要哪幾格。

**這幾條規矩住在哪一份，看這件工作落在誰身上。** 落在這套流程自己身上（skill、它們的
腳本、常駐規則）的話，那一份是 `framework-self-dev`——它說出為什麼是這兩種、查重的鍵
為什麼是檔案而不是標題。落在別的東西上的話，那個東西自己的知識說了算。

它不簽 assertion、不決定領域、不開 worktree、不碰你現在這張單。產出的單會出現在下面〈四〉
那個「接下來做哪一張」的答案裡，標成 `seed:`——所以它拿得給另一個 session 開工，而那個
session 從 `refinement` 開始。

**已經在進行中的單不要重問。** 同一件事往下做就是了——對已經簽過的東西再問一次是儀式，
不是把關。換成另一件會改變行為的事，才重新判斷。

## 二、現在在哪、下一步是什麼

不要問人，讀狀態：

```bash
bash .claude/skills/driving-work-to-done/scripts/spine-loop-state.sh where --state {issue}/.spine/loop-state.json
```

它會說出站別、有沒有停、還剩幾輪。**任何時候不確定現在在哪就跑它**——問人才是不知道
自己在哪的那個症狀。

它同時回答另一個「在哪」：**這個工作區還是不是這張單當初落腳的那些。** 開輪次那一刻
記下的身分由領域決定（核心只當它是一組不透明字串），之後每次問路都比一次。**那是一組，
不是一個**——一張單牽涉幾個地方由領域宣告的命令印幾行決定，核心不預設是一個。回 `DRIFTED`
表示現在動手的地方跟這張單預期的不同（少一個、多一個、值不同都算，而且它會說出少了哪些、
多了哪些）——可能是有人切走了，也可能是另一個 session 正在共用同一份工作區。回
`unmeasurable` 表示這一次什麼都沒比到，那不是「還在原地」。

| 現在的狀況 | 下一步 |
|---|---|
| 還沒有單 | `refinement`：判立案、寫 assertion、凍結、開輪次 |
| assertion 凍結好了 | `engineering` |
| 這一輪做完了、想知道算不算達成 | `verify-ac` |
| `verify-ac` 判非 PASS，原因是實作沒到 | 回 `engineering` |
| `verify-ac` 判非 PASS，原因是**assertion 本身錯了** | 停 `assertion_wrong`，回 `refinement` 重簽 |
| 交付紀錄寫成了 | 這條流程走完了。之後怎麼出貨是專案自己的事 |
| 交付紀錄寫成了，而後來有人指出還要改的東西 | 回 `engineering`。改完**重走 `verify-ac`**——那一站要量的是改完之後的東西，不是上一次留下的判定 |
| 這件事**不做了**（放棄、被別的取代、需求消失） | `close`，見下方 |

**交付之後還要改，不是一個新的開始，也不是一個停點。** 那張單的成功定義沒有變——變的是
「實作有沒有走到那份定義」這個問題的答案。所以它回 `engineering`，而不是回 `refinement`
重簽、也不是另開一張單：另開一張的話，同一份 assertion 會有兩張單各自宣稱自己達成了它。

**回去之後一定要重走判定。** 上一次的判定是對上一棵樹下的，而它會留在原地看起來仍然有效
——一份綁在舊狀態上的 PASS，跟一份剛量出來的 PASS 長得一模一樣。真的是成功的定義本身錯了
（不是實作沒到），那才是 `assertion_wrong`，走上面那一列。

**「不做了」是一個終點，不是一個停點。** 四種停點都在等人回話，而這一種已經有答案了——
它只是不會有實作。以前這種單沒有地方去：要嘛永遠躺在待辦裡被每一次「下一張做哪個」重新
看過一遍，要嘛被手動刪掉，而刪掉的那一張在下一次有人提出同一件事時說不出「這討論過」。

```bash
bash .claude/skills/driving-work-to-done/scripts/spine-loop-state.sh close \
  --state {issue}/.spine/loop-state.json --note '<為什麼不做了>' [--by <人>]
```

理由是必填的：一個沒有理由的關閉，跟把單刪掉的差別只有磁碟空間。已經收斂的單它會拒絕——
那張是做完的，不是不做的，而把兩者混成同一格之後就沒有人分得出來了。

**換站不需要說服任何腳本。** `advance` 是記下來，不是請求核准。還會擋人的只有兩類：
不可逆的動作，以及證據不足。

## 三、只在四個地方停

流程停下來的時候要說出是哪一種，而且要留下紀錄——**停在紀錄外等於沒停**，回來的人只
看得到一張不動的單，看不到它為什麼不動。

| 停點 | `--kind` |
|---|---|
| assertion 不對，要人重簽 | `assertion_wrong` |
| 新增依賴／重造既有組件／擴大 security surface | `surfaced_concern` |
| 連續未收斂打到上限 | `unconverged_cap`（`record` 自己會寫） |
| 需要人授權的不可逆動作 | `unauthorized_action` |

```bash
bash .claude/skills/driving-work-to-done/scripts/spine-loop-state.sh stop \
  --state {issue}/.spine/loop-state.json --kind surfaced_concern --note '<一句話>'
```

這四種以外的字串會被拒絕。**這四種以外的理由不是停下來的理由**——特別不包括「要不要
繼續？」「要我往下做嗎？」，那不是停點，那是把判斷推回給人。

## 四、沒撞停點就繼續

**沒有停點就往下走，不要回頭問。** 這包含跨單：手上有多張單而當下這張走不動了，
下一張由同一個地方回答，不是由人指定。

```bash
# 這一張單還能不能往下走
bash .claude/skills/driving-work-to-done/scripts/spine-loop-state.sh next --state {issue}/.spine/loop-state.json

# 手上這一整棵樹，接下來做哪一張
bash .claude/skills/driving-work-to-done/scripts/spine-loop-state.sh next --across-issues issues
```

單張回 `continue` 就繼續，回 `stop:<kind>` 才停。跨單回 `next:{那張單相對於樹根的位置}`——
它是拿去開檔案用的，**不是身分**：一張單的身分是它的名字，位置會隨狀態改變。並且把停住
的逐張列出來、把已收斂與已交付的算成數字——**不列成清單但要有數字**，一個安靜的第三態下一次
就會被當成看過了。

**種子單也逐張列出來**（`seed:` 開頭），不只算進數字。它們還沒簽 assertion，所以接手的第一站
是 `refinement` 而不是 `engineering`；而它們存在的整個理由就是「拿給另一個 session 開工」，
掉出這個答案的東西等於沒開。

**幾個數字加起來要等於整棵樹。** 一張單的狀態不一定住在這裡——命名空間宣告了解析器的，
權威在那個外部系統。那些單走不進站別，但它們仍然是單，所以它們有自己的數字，而不是消失：
最後一行把等式寫出來，分母是位置重算認得的那組單，不由這裡再數一次。**逐張的清單只有一
份**，在重算產出的那份「還沒出去的單」上——這裡指過去，不抄第二遍。

那個等式不是裝飾。2026-08-21 量到，這個答案只涵蓋 700 張單裡的 555 張，差的 145 張裡有
121 張還在中間態，包含正在進行的工作；而它們不在任何一格、也不在任何一個數字裡，輸出看
起來完全正常。少算的方向剛好是「看起來事情比較少」，所以沒有人會抱怨。

排序只看狀態：最靠近交付的先做（在製品不該堆高），同一站取最近動過的那張（那是「你剛剛在做
哪一張」寫在磁碟上的唯一痕跡）。命名空間叫什麼、單號多大都不參與。

**流程自己的工具擋住你的時候，那不是停點。** 一道關卡對一份已經被實證是對的交付判紅，是那
道關卡的缺陷，處理是修它然後繼續——把摩擦寫進可以改的那部分、把修法做掉。停在「被框架擋住了，你要
不要開一張單」等於把工具的問題變成人的決定，而工具是來幫忙的，不是來收費的。

同一件事的另一面：**關卡判紅而你想繞過它的時候，先把產出改成它接受的樣子**，不要把「用哪個
繞法」做成問題丟回去。關卡是權威，繞過去才需要人點頭。

### 寫摩擦的時候指名是哪一支

「這一套東西有沒有讓工作更常做對」只能從真的跑過的那幾次讀出來，而**寫的時候不指名，事後
就讀不出來**。2026-08-13 量到的：1,721 份單的正文裡有 345 份寫了摩擦，其中 323 份文件裡同時
出現某支 skill 的名字——但那是同現，不是歸因。一張走主流程的單本來就會提到 `refinement` 與
`engineering`，所以那 323 份回答不了「是哪一支害的」。**素材有量，形狀不對。**

所以摩擦與幫助各記一行，就寫在可以改的那部分裡，格式是：

```
<!-- SKILL-UTILITY: {skill 名} | helped|hurt | {一句話：發生了什麼} -->
```

**兩個方向都要記。** 只記摩擦的話，讀出來的結論永遠是「這套東西都在擋人」——而
2026-08-13 那一趟裡，兩次擋下真正不可逆的後果（公司代號要進公開 repo、副本漂開）跟六次
擋下正確的工作，是同一批紀錄該說出來的兩半。

讀它不需要工具：`grep -rn 'SKILL-UTILITY' <單的根目錄>`。**不要為它寫一支腳本**——它不擋任何
人，它是拿來讀的；一個會擋人的 utility 判準會在第三次被繞過。

**它記得到的只有走過單的工作。** 沒有立案就用掉的那些（查一下、跑個報告、看一次收件匣）
不留這種紀錄，所以這一份紀錄天生偏向「會改程式碼的工作」。這是已知的覆蓋缺口，讀結論的時候
要把它說出來，不要把「沒有紀錄」讀成「沒有問題」。

反覆出現的失敗長這樣，看到就是退化了：

- 把連續的意圖收斂成單步，做完一步就停下來報告；
- 停在階段邊界等人說「好」；
- 用一句「要不要繼續？」把判斷推回給人。

## 四之二、每一張本地開的單都帶著號

沒有號的單排不進待辦、也沒有一個穩定的東西給別的單引用，而它會一直長出來，到某次盤點才
被一次找到一批。**號不需要人記，也不需要任何新的宣告**——開單那條路自己算：

```bash
bash .claude/skills/driving-work-to-done/scripts/next-ticket-number.sh \
  --issues <單的根目錄> --namespace <命名空間>
```

判準是樹裡已經有的東西：**宣告了狀態解析器的命名空間，它的單來自外部系統**，號也一樣來自
那裡——本地鑄造一個出來，下一個人會拿它去那個系統搜，然後搜到別的東西或什麼都沒有。沒宣告
的命名空間，本地就是權威，取現有最大號加一。

**照著它算一個號再自己建目錄，是開單的第二條路。** 走這一條的話，上面〈手上正在做別的
事〉那幾件事沒有東西替你做——種類、6W、查重、判斷，四樣都要自己做完再建目錄。那一份說
清楚要做什麼的知識跟著這件工作落在誰身上走：落在這套流程自己身上的是
`framework-self-dev`。

所以「這件事該開在哪個命名空間」有一個乾脆的答案：**改框架本身的工作（skill、腳本、規則）
就是框架的工作**，即使它講的內容是某一家公司的；產品工作的單來自那家公司的系統，我們從來
不鑄造那種號。2026-08-08 有兩張改 `.claude/skills/` 的單因為「內容跟某家公司有關」被放進
那家公司的命名空間，於是它們永遠拿不到號。

## 四之三、一張單住在哪

**位置是一個推導出來的答案，不是一個會被執行的搬動。** 重算算出每一張單該在哪一格，
把那個答案寫進那張單自己的 `{單}/.spine/placement.json` 與人看的那份清單——**它不搬任何目錄**。
所以樹上的路徑說的是這張單當初被放在哪，`placement.json` 說的是它現在的狀態該在哪，兩者
對不上是常態，不是一個要被修好的錯誤。

以前重算會真的搬。拿掉那一半是因為它自己製造了它要解決的問題：一次沒搬完的搬動留下一個
空殼，而那個空殼從此是同一個單號的第二條路徑，於是同一張單有兩份 `placement.json` 說不
同的話。要人自己搬的話，搬錯了只是搬錯了；讓重算搬，錯的那一份會安靜地變成下一次推導的
輸入。

**路徑投影的是歸屬，格子投影的是鏈頂那張單的狀態。** 一張單有母單的話，它住在母單底下：
`{命名空間}/{格}/[{日期}/]{鏈頂}/…/{它自己}`，中間每一層都是一個單號。母單鏈有幾層就有
幾層，不並排成一層。

**子單不因為自己的狀態算到別的地方去。** 同一個母單底下的子單狀態各不相同是常態——各自
算一格的話，那個母單就被切成好幾塊，而它正是人拿來理解工作的單位。子單自己的狀態沒有消失，
它算得出來，寫在那張單的 `placement.json` 與人看的那份清單上。

**鏈上出現、樹裡還沒有的母單，重算逐張說出來，不補。** 以前它會把那些目錄造出來——而一個
只當路徑用、沒有內容的母單層，翻樹的人在它身上讀不到任何東西，機器又會把它算成一張單。
要不要開那張單是人的決定。

**單底下不是每一個目錄都是單。** 帶著 `.spine/` 的才是。少了這道判準，舊層留在單裡的那些
工作目錄會被一個一個算成單，然後被指名成一個不存在的重複。

**但「不是單」與「不要穿過去」是兩件事。** 不是單的目錄照樣要走進去看——樹上有一些只當路徑
用的中間層（沒有 `.spine/`、沒有正文，只有一個子單目錄，多半是過去那些搬動留下的），而在
那裡停下來的話，底下的單就永遠不進清單。那是一個會自己維持住的洞：孫單看不見 → 它的歸屬鏈
沒有人讀 → 孫單繼續看不見。2026-08-21 真樹上因此漏掉 19 張。

**位置是狀態的投影，不是第二個權威。** 一張單在哪一格由它自己的狀態算出來——所以要問「這張
單走到哪了」，讀那份紀錄，不要讀它躺在哪個資料夾。**手動搬一張單，重算不會把它搬回去，也
不會抱怨**：它只會照著新的路徑再算一次。

**重算說，人搬。** `record` 寫完輪次就重算一次，把每一張單該在的那一格算出來、寫回去：

```bash
bash .claude/skills/driving-work-to-done/scripts/place-issues-by-state.sh --issues <單的根目錄> --check
bash .claude/skills/driving-work-to-done/scripts/place-issues-by-state.sh --issues <單的根目錄> --execute
```

**兩種模式的差別只有寫不寫紀錄**：`--check` 什麼都不寫、有落差就 exit 1；`--execute` 把
推導結果寫回每一張單並重寫清單。**兩種都不搬任何目錄。**

**格子叫什麼不寫在散文裡。** 那份清單是那支腳本自己的，`--check` 會把每一格與各裝幾張印
出來。抄一份到文件裡就有兩個答案，而漂掉的那一刻沒有人在看。

推導出來的結果會寫回**單現在所在的那個目錄**（`{單}/.spine/placement.json`）——不是它「該
去」的那條路徑。所以一張單只有一份紀錄，而讀那份紀錄的程式走到單所在的地方就讀得到它。
位置給人看，那份紀錄給程式讀，
兩者同一次推導產出，所以不會有第二個答案。**任何要問「這張單收斂了沒」的程式讀那一份，
不准從資料夾名推狀態**——那條路徑一多一層資料夾就會靜靜地失效。

### 兩層推導，問不到就說出來

1. **走過主流程的單**：`{單}/.spine/loop-state.json` 就是權威，不需要問任何人。
2. **沒走過的**：問那個命名空間自己宣告出來的解析器。宣告長這樣，掃的是所有 skill 的
   `SKILL.md`：

   ```
   <!-- {任意前綴}-ISSUE-STATE-{命名空間}: {命令} -->
   ```

   **核心不認得任何一個外部系統，也不認得任何一個外部狀態名。** 換一個地方只要換那一行。

順序不能反：主流程的答案是本地的、確定的，讓一趟網路往返有機會覆蓋它，等於把權威交給一個會
逾時的東西。**問不到不得讓重算說謊**——那些單落進「等人歸位」那一格並被指名「這次沒問到」，
不沿用上一次的答案，也不讓整支停掉。

兩層都問不到的目錄（主流程之前的舊層、還沒開輪次的種子）**不參與位置判定，留在原地**，但
數量每次都會被印出來——**那個數字由那一次重算自己印，不寫在散文裡**。把它們全掃進「等人
歸位」那一格會讓那一格裝進幾百張，而那一格存在的意義是「機器問過了、答不出來、等人歸位」，
一個沒人看得完的抽屜等於沒有這一格。一個不被判定的第三態如果安靜，下一次就會有人以為那些
目錄都被檢查過了。

### 終局那幾格

**做完了、出去了、不做了是三件事，不是同一件。**「不做了」以前沒有地方放，於是它要嘛永遠
躺在待辦裡被每一次〈四〉重新看過一遍，要嘛被人手動刪掉——而刪掉的那一張，下一次有人提出
同一件事時說不出「這討論過，結論是不做」。走進那一格的方式是上面〈二〉的 `close`。

終局那幾格底下多一層日期：任何終局都該知道時間，一格裝一百張只能照名字翻。查不出日期的
放進 `undated/`——把整理它們的那天填進去，會讓一個看得出來的空白變成一個看不出來的謊。

**但日期那一層不判定任何事。** 它是給人翻的，不是第二個權威——一張單走到哪一種終局，看的是
它自己的狀態與紀錄，不是它落在哪個資料夾。

`{單的根目錄}/OPEN.md` 是同一次重算產出的人看版本：所有還在中間態的單，逐張帶著它在哪一格、
位置依據什麼推出來、上次動過多久、是不是自己的單。**停滯只出現在那份清單上**——一張在同一
格待了兩個月的單，那一格就是它正確的位置，「這樣算不算太久」由看的人決定，不由門檻代人
搬走它。

## 五、載入領域知識：這類工作怎麼算 done

`refinement` 判完要立案之後，判斷這件工作屬於哪個領域，載入對應的知識，**並把載了什麼
記在單的狀態裡**。

| 這件工作 | 載入 |
|---|---|
| 會改到程式碼、要進版控 | `swe-knowledge` |
| 不會改程式碼（報告、調查、文件、資料分析） | 沒有適用的領域 |

領域的決定**就在開輪次那一步**，不是之後補的欄位。**這張單的改動會落在哪些地方也是**：

```bash
bash .claude/skills/driving-work-to-done/scripts/spine-loop-state.sh init \
  --state {issue}/.spine/loop-state.json --pack swe-knowledge \
  --where <工作區路徑> [--where <另一個>]...
bash .claude/skills/driving-work-to-done/scripts/spine-loop-state.sh init \
  --state {issue}/.spine/loop-state.json --pack none --why '<為什麼這件工作沒有領域完成條件>'
```

`--where` 給幾次就是幾個地方，值是不透明字串——核心把它記下來，之後每次問路原樣交還給
領域的腳本去求值。**它不是「我現在站在哪」，是「這張單的改動會落在哪」**：一張單住在
`issues/` 而程式碼落在某個產品 repo 是常態，兩者不是同一個地方。宣告不出來就不開輪次，
因為從當下位置推出來的那一份對這種單永遠是錯的那一邊，而它之後每次比對都自洽。

需要知道這張單落在哪裡的時候讀這一支，**不要自己再推一次**：

```bash
bash .claude/skills/driving-work-to-done/scripts/spine-loop-state.sh landing \
  --state {issue}/.spine/loop-state.json
```

DP-482 之前開的單狀態裡沒有這份宣告，問路會回 `unlanded`。補記（或在落腳處真的變了的時候
改記，改要帶人的原話）：

```bash
bash .claude/skills/driving-work-to-done/scripts/spine-loop-state.sh land \
  --state {issue}/.spine/loop-state.json --where <工作區路徑> [--authorization '<人的原話>']
```

`init` 還會跑那個領域宣告的**開工條件**——條件寫在 pack 自己的知識裡，核心只負責找到它、
跑它、不成立就拒絕開輪次。所以核心不認得任何一個領域的條件，換一個領域不用動核心。

它也會拒絕**在同一個地方開第二輪**：同一棵單的目錄樹裡已經有一張走到終局站別的單，而它記下的
身分與現在求出的有**任何一個交集**，就不開。交集就夠了——共用其中任何一個地方，新的一輪
就疊在別人的歷史上，最後只能一起出去。這件事 2026-08-03 真的發生過一次，三份交付紀錄釘在
同一個 head，而中間沒有任何一步說過話。拒絕訊息會指名是哪一張單、交集在哪，以及往下走的
兩條路（把那張單走完，或換一個工作區）。

中途要改判領域（做著做著發現它其實會動到程式碼）用這一支，它是覆蓋不是追加：

```bash
bash .claude/skills/driving-work-to-done/scripts/record-knowledge-pack.sh record \
  --state {issue}/.spine/loop-state.json --pack swe-knowledge
```

**「沒有適用的領域」是一個被記下來的選擇，不是欄位空著。** 兩者在檔案裡長得不一樣，
在報告裡也要長得不一樣。

**指名的 pack 載不到就停，不要照常往下走。** 散文說「去載 X」而 X 不在，是完全安靜的：
routing 照樣把工作分派出去，只是分派到一份從未被讀取的程序。這個 repo 有過六支 skill
整段存在期間零載入而沒有人發現。`record-knowledge-pack.sh` 會拒絕一個解析不到 SKILL.md
的 pack 名字——它擋的就是這件事。

## 五之二、這一趟是誰在跑

`init`／`advance`／`record` 寫輪次狀態的時候，順手把「這一趟是誰在跑」記進
`{issue}/.spine/loop-state.json` 的 `holders[]`。**核心不認得任何一種對象**——它掃所有
`SKILL.md` 找這一行，跑它，把印出來的第一行原樣記下來：

```
<!-- {任意前綴}-ACTOR-IDENTITY: {命令} -->
```

形狀跟 `ISSUE-STATE-{命名空間}` 是同一套，但沒有後綴：「現在是誰在跑這一趟」只有一個答案，
而「這張單在哪一格」每個命名空間各有各的權威。**沒有人宣告是一個答案，不是壞掉**——那個
環境裡沒有東西回答得出這個問題，於是它記下這句話，往下走。

為什麼掛在這三個動作上：它們是流程走不過去就不能繼續的三步，所以「凡是走過流程的單都有」。
掛在一份自願寫的宣告上的話，覆蓋率就是「記得寫的那幾個」。

**不覆寫，逐個對象各佔一格。** 只有開輪次那一步寫的話，一張單換手之後那一格永遠是開單
的那個人；每次都覆寫的話，最後一個路過的人就成了「誰在做」。而覆寫的那一版連「不只一個
對象接著同一張單」都表達不出來——那正是要被看見的東西，不是要被收斂成一個的東西。

**推不出來的時候記下理由，不記一個空字串。** 空字串跟「沒有人接」在檔案裡長得一模一樣，
而它們要人做的事不同：一個是去看為什麼推不出來，一個是去找人接。

**這一格不判定任何事。** 它不改變任何一張單走到哪一站，也不是第二個回答「這張單在哪一格」
的地方——那個答案只有一個權威。誰讀它、怎麼印，是讀的那一端的事。

## 六、這一組東西要能整包搬走

`driving-work-to-done` ＋ `refinement` ＋ `engineering` ＋ `verify-ac` ＋ 領域 pack，複製到
另一個 repo 就能用。所以：

- **每一句指令都指向這一組 skill 目錄裡的東西**，不指向 repo 根目錄的腳本、常駐規則、
  或任何 git hook。那些在 claude.ai 與 Cowork 不存在——而指過去的那一刻不會有人報錯，
  只會安靜地讀不到。
- **不假設命名空間叫什麼**。`issues/{命名空間}/{單}/` 的中間那一段是誰決定的都不影響判定。
- **不假設領域**。核心的散文裡不出現只有軟體工程才成立的詞——它們屬於 `swe-knowledge`，
  不屬於這裡。

**這三件事沒有關卡在守，是刻意的。** 以前有一道 `gate-layer-vocabulary` 掃三行宣告，
判「哪些詞不得出現在哪幾支 skill 的散文裡」——那是一段散文在規定另一段散文：它擋不住任何不可逆的事，
但每一次無關的改動都要付錢。判準留在這裡給寫的人讀，寫錯層的代價由「有人把那一層單獨
搬走的時候帶不動」承擔，不由一道關卡代人承擔。

三種寫錯層的方式：

- **核心的散文出現只有軟體工程才成立的詞**（branch、pull request、merge、CI、deploy）。
  唯一的例外是凍結用的 `git commit`：凍結的簽名就是那個 commit，跟領域無關。
- **反過來，核心自己的詞出現在某一個產品的知識裡**（停點怎麼分類、輪次狀態檔叫什麼）。
  一支產品 skill 重講這些，那段話就不屬於它——它在別的產品也成立，複製過去的那一份會跟
  這裡漂開。例外是**指過來**：說「這件事走 `driving-work-to-done`」是路標，不是複製；
  判準是它有沒有自己重講一次那些詞的意思。
- **領域 pack 出現只有某一家公司才成立的東西**。公司樣式由每一家自己的
  `workspace-config.yaml` 說了算，不在這裡抄第二份。

## 這裡不做的事

- **不判定達成**。那是 `verify-ac`，它有 oracle。
- **不決定量測命令**。那是 `engineering` 的活區。
- **不出貨**。交付紀錄寫成就是這條流程的終點，釋出尾段屬專案私有。
