driving-work-to-done · diff
v1.0.0 to v1.0.0
13 added, 0 removed. Audit A to A.
---
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/` 的單因為「內容跟某家公司有關」被放進
那家公司的命名空間,於是它們永遠拿不到號。
## 四之三、一張單住在哪
**位置是狀態的投影,而 `--execute` 會把投影落地——但只落在它證明得了身分的那幾張上。**
重算算出每一張單該在哪一格,把那個答案寫進那張單自己的 `{單}/.spine/placement.json` 與人看
的那份清單,然後把**搬得動**的資料夾搬過去。
**搬得動要先證明,四項缺一就不搬**:這張單是鏈頂、身上有 `.spine/`、它的單號在整棵樹裡只有
一條路徑、目的地還不存在。任何一項不成立就留在原地,而報告會逐張說出卡的是哪一項。
四項各自擋掉一種真的發生過的事。DP-661 曾經把搬動整個拿掉,因為那一半自己製造了它要解決的
問題:一次沒搬完的搬動留下一個空殼,而那個空殼從此是同一個單號的第二條路徑,於是同一張單
有兩份 `placement.json` 說不同的話。**這一版不靠「搬得比較小心」把它擋回去**——擋回去的是
那四項先決條件,它們在搬之前就答得出來。
**搬動用檔案系統的更名,不是 `git mv`。** 單的那棵樹是好幾個工作階段共用的,而 `git mv` 會把
改動放進共用的索引,別人下一次送出就會把它一起帶走。更名之後 git 自己認得出改名,而索引一個
字都沒有被動過。
+ **搬完之後,搬它的那一支自己把那次搬動 commit 進去。** 少了這一步,被搬的單只活在一個沒有
+ 任何 commit 指著的路徑上——舊路徑在 git 眼裡是 `D`、新路徑是 `??`;任何人跑一次
+ `git clean -fd`,那些目錄整個消失,而 `git checkout -- .` 只救得回舊路徑那一份。這件事
+ 2026-09-06 一天內發生兩次,一次在釋出尾段、一次在關單那條路——**所以修的是搬動這一支,
+ 不是它的某一個呼叫端**:三個呼叫端各修一次的話,漏掉的那一條不會爆炸,只會安靜地少一筆。
+
+ 那顆 commit 只帶被搬的那幾張單的路徑(舊的與新的各一條),因為單的那棵樹是共用的:
+ `git add -A` 收整棵樹,不帶 pathspec 的 `git commit` 送出整個索引,兩者都會以這一次搬動的
+ 名義帶走別人手上還沒 commit 的東西。**沒有搬動的那些重算一個 commit 都不寫**——而重算被
+ 記一輪順手觸發是常態,所以那個條件不是省事,是這一段能掛在這裡的前提。
+
+ 單的那棵樹不是 git repo 的時候它說出來,然後照常完成重算:**問不到不得讓它安靜地不做。**
+
**路徑投影的是歸屬,格子投影的是鏈頂那張單的狀態。** 一張單有母單的話,它住在母單底下:
`{命名空間}/{格}/[{日期}/]{鏈頂}/…/{它自己}`,中間每一層都是一個單號。母單鏈有幾層就有
幾層,不並排成一層。
**子單不因為自己的狀態算到別的地方去。** 同一個母單底下的子單狀態各不相同是常態——各自
算一格的話,那個母單就被切成好幾塊,而它正是人拿來理解工作的單位。子單自己的狀態沒有消失,
它算得出來,寫在那張單的 `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` 把推導結果寫回每一張單、重寫清單,並把四項先決條件都成立的那幾張搬到算出來的
那一格。**推導結果跟上一次一樣的那些單,`--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` 的活區。
- **不出貨**。交付紀錄寫成就是這條流程的終點,釋出尾段屬專案私有。