Version Sequencing
規格完備之後、第一張實作票之前的全盤排序工作流。產物是一串整合測試的順序,以及首版的可派發票。每個版本對應一個整合測試,該測試全綠即版本完成。
它防的失效形態:使用者急著寫程式看結果,跳過整體規劃直接開工,功能之間的依賴在實作中才逐一撞見。
版本層級用語:中版本承載一個方向(對應一個整合測試),小版本是中版本內的修正。
四條不變量(本 skill 的全部承諾)
| # | 不變量 | 防什麼 |
|---|---|---|
| 1 | 每版一個整合測試作為完成定義 | 「這版好了沒」變成有客觀答案的問題,不是感覺題 |
| 2 | 序列是順序,不是閘門 | 開工不需要先想完所有情況;未預期的變體進小版本修正 |
| 3 | 延後的決策必須綁 ticket | 待決事項有觀察者;「以後再說」不會變成永遠不會被觸發的清單 |
| 4 | 驗收斷言指名外部固定值 | oracle(判定對錯的標準答案)不在執行者手上;否則空實作也能讓驗收全綠 |
不變量 4 對散文型產物的落地形態
規格、提案、skill 這類散文產物沒有測試可跑,但仍適用不變量 4。對散文,外部固定值的形態是可重跑的命令與其固定輸出:
| 散文型驗收 | 不合格(oracle 在執行者手上) | 合格(外部固定值) |
|---|---|---|
| 這份文件審過了嗎 | 「三輪都完成了」 | frame 判定表逐格有記錄;每條 finding 附一條可重跑命令與其輸出 |
| 這個引用正確嗎 | 「確認過了」 | test -f <path> 為真;grep -c <錨點> <path> 非零 |
| 這個宣稱成立嗎 | 「查證屬實」 | grep -c seed state-storage.md = 0 |
缺這個形態的後果:沒有外部固定值可判定「審過了沒」,就沒有東西擋得住 push。本 skill 的第一步要求規格文件走審查,而規格文件正是散文;此形態未定義時,該要求無法被驗證是否履行。
不變量 2 的適用上限
實作發現切分軸本身失效時(例如管線的某一段根本不存在),該回頭改序列,此時不適用不變量 2。 判別問「這個發現推翻的是某一版的內容,還是版本之間的依賴」。前者進小版本,後者重排序列;兩者同時被推翻時以後者為準,因為依賴錯了,內容對不對已不重要。
附註:不變量 2 的前半(不必先清空待決)可由不變量 1 與 3 推出,每版有完成定義且待決有觀察者時,未清空的待決不會靜默消失。後半(未預期變體進小版本、不回頭改序列)是獨立承諾。
不變量 1 對小版本的適用
小版本是修正不是新能力,不另立整合測試,但必須有一條測試涵蓋它修的那個變體,併入所屬中版本的整合測試。該條測試由小版本票的驗收條件承載,未附此測試的小版本票不得完成。
刻意不綁定完整敏捷流程。 這四條與 scrum、sprint、story point 全部無關。把整套敏捷綁進來等於把方法論偏好硬編進工作流,而偏瀑布的使用者用這四條照樣成立。「中版本定方向、小版本做調整」可由四條推出,不是額外規則。
六步工作流
1. 規格完備檢查(必經 multi-round-review)
對全部規格文件執行 multi-round-review skill(至少三輪,frame 切換)。這一步不可省:審查的價值是把「本來就在、只是沒被寫下來」的待決事項拓出來,把文件改乾淨只是副產品。單輪或人工盤點會漏掉結構性不可見的三類:未被寫下的內容、跨篇皆未承接的前提、只在真實個案上才停住的判準。
輸入集合:專案的全部規格層文件。判準是「描述系統該做什麼、且下游會據以實作的文件」——提案、規格、使用案例、domain 邊界文件屬之;變更記錄、流程規範、建置指令不屬之(它們記做過什麼與怎麼做,不記該做什麼)。開始前先把清單列出來,審查範圍以此為準。
frame 指審查時採取的提問角度(例如事實查核、冷讀、情境可想像性、自我適用)。frame 切換指每一輪換一組角度,使各輪的 finding 不重疊。停止判準見 multi-round-review skill;做完的判準不是輪數,是停止訊號成立。
產出契約:待決清單,每項標明「它擋住哪一個能力」。沒有標阻擋對象的待決不算收束完成。清單需有持久載體(決策記錄文件或 ticket 皆可),且步驟 4 逐項取用時以該載體為輸入。留在對話中的清單在步驟 4 無法被取用,等同未產出。
2. 選切分軸
候選軸至少三個。下表即三個候選,可直接採用為候選集,但仍須比較後擇一,不得因表已列出而略過比較:
| 軸 | 特性 |
|---|---|
| 資料管線 | 與 domain 依賴圖同構。前一段綠了下一段才有輸入,「這版能不能開始」有客觀答案。多數專案的預設傾向 |
| 畫面 | 每版有可見成果,但每個畫面各自把整條管線帶起來,前幾版重複建同樣的地基 |
| 使用案例(UC) | 驗收條件現成,但 UC 之間共用大量基礎設施,切分邊界反覆重疊 |
預設傾向不豁免比較。專案形態(純後端、純工具、資料密集)會改變答案。
比較工具:wrap-decision skill(W 階段擴增選項 + premortem)。需結構化評分時改用 design-decision-framework skill。兩者目前彼此零引用,這是已知的框架缺口,不是讀者需要解決的分歧。
最小合格產出:選定的軸,加上未選中的各軸為什麼不選。不選的理由須各指名本專案的一個具體物件(哪個畫面、哪個 UC、哪一段管線);只複述上表特性欄不算比較。
3. 版本序列落為提案
序列寫成一份提案文件(走專案的提案機制),每個版本三件事齊備:
| 欄位 | 內容 |
|---|---|
| 整合測試斷言 | 這版全綠的判準是什麼,指名外部固定值(真實語料的已知答案、可重跑的計數),不接受「執行者自己說做完了」 |
| 斷言來源文件 | 斷言取自哪份規格(狀態矩陣、事件契約……),使測試與規格互相追溯 |
| 阻擋清單 | 已知的未知。標明本地待決或外部依賴,不要求開工前清空(見不變量 2) |
版本啟動閘門:某版的提案缺整合測試斷言、或斷言未指名外部固定值時,該版不得開出任何實作票。這是不變量 1 的觀察者,形態是前置條件而非動作,因此不需要另一個觀察者來保證它發生。
首版是地基版,除非該版的提案不含任何地基產物。foundation-design skill 的產物票在「首版開票」那一步開出,功能票 blockedBy 它們。
4. 待決綁版本
步驟 1 的待決清單逐項綁到「它擋住的那個版本」,載體是 ticket 與 blockedBy。時間、量化閾值、外部事件都不是合法 trigger,須先包裝為 ticket(同專案的決策 trigger 綁定規則)。
外部依賴(上游 repo 的票)標為 external blocker,不混入本地待辦。綁定方向:建一張本地追蹤票,該票 blockedBy 外部依賴;受阻的版本再 blockedBy 該追蹤票。不要讓版本直接 blockedBy 外部物件,外部定案時沒有本地載體會浮現。
為什麼不「現在一次全部解決」:多項待決在沒有實作經驗前定不準,定完又改。為什麼不「碰到再說」:無觀察者的待決會持續無人觸發,直到以事故形式被動浮現。綁版本是兩者之間唯一有觸發機制的選項。
5. 首版開票
- 一票一事(atomic):一個 action + 一個 target。標題含連接詞「與」「和」是拆分訊號
- 地基波(W1)先行,功能波(W2)內各票儘量互不相依、可並行。「波」指一批可同時開始的票,不是時間單位
- 票的 why 寫「這件事為什麼難」而非重述它是什麼。把步驟 1 審查的發現落進票面,執行者不必重走一次發現過程
- 驗收條件指名外部固定值(同步驟 3 的原則),並警惕「資料來源缺席時驗收反而更好過」的形態。對照函式永遠回空也能讓「逐項標記」類驗收全數通過
6. 序列維護
| 事件 | 動作 | 誰在何時檢查 |
|---|---|---|
| 實作撞到規格未預估的變體 | 開小版本票修正並回填規格 | 撞到的執行者當場開票;事件自帶觸發,無須額外觀察者 |
| 外部依賴(external blocker)定案 | 回頭確認對應版本的阻擋是否解除、定案內容是否改變順序 | 步驟 4 建立的本地追蹤票,blockedBy 綁定使其定案時浮現 |
| 某版的整合測試遲遲無法定義 | 那是真阻擋,該版的前置待決此時才需要先做 | 步驟 3 的版本啟動閘門。斷言未就緒即無法開票,狀態本身即訊號 |
「誰在何時檢查」欄必須填具體承擔者(票、事件、或前置條件),不能填動作。動作不能保證自己發生。
與其他 skill 的分工
| skill | 關係 |
|---|---|
multi-round-review skill |
步驟 1 的必經工具 |
wrap-decision skill |
步驟 2 的比較工具(含 premortem) |
foundation-design skill |
地基票的入口與內容來源。它是路由層,逐維度決定本專案的地基產物是什麼;本 skill 在「版本序列落為提案」那一步決定這些票屬於哪一版,在「首版開票」那一步開出。同一批票,兩邊不重複建 |
version-bootstrap skill |
下游。本 skill 產出版本序列與各版提案;version-bootstrap 執行該版的規劃波展開。其 pipeline 含本 skill 未涵蓋的步驟,交接後由它負責 |
層名約定:foundation-design 是路由層(指名權威、定每個維度的產物);version-bootstrap 是編排層(在規劃流程的特定步驟安排執行);本 skill 是排序層(決定各版順序)。三者不同名不同職。
與 version-bootstrap 的交接契約(三項,缺一則下游的強制檢查會空跑通過):
| 交接物 | 本框架的位置 | 由誰寫入 | 誰在何時檢查 |
|---|---|---|---|
| 該版的提案清單 | docs/todolist.yaml 該版本的 proposals |
本 skill 步驟 3,於該版啟動時寫入 | 版本啟動閘門(步驟 3):清單為空即不得開票 |
| 提案間的依賴 | docs/proposals-tracking.yaml 各提案的 depends_on |
本 skill 步驟 4 綁定待決時一併回填 | 步驟 4 的完成條件。無依賴時須顯式寫 depends_on: [] 而非留 null,否則「確認無依賴」與「未回填」在下游輸出同形 |
| 提案的目標版本 | 同上的 target_version |
同上 | 同上。序列已定而此欄為 null 時,下游無從驗證排序矛盾 |
為什麼「誰在何時檢查」欄不可省:version-bootstrap 的跨提案依賴檢查讀 depends_on 比對 target_version。實測 depends_on 零筆的專案,該檢查回報 [OK] 無跨提案依賴排序矛盾、exit=0,與真正檢查過完全同形。回填未發生時沒有任何輸出會提醒。
位置欄是本框架的慣例,不是契約本身。 契約的內容是那三項資訊必須存在且可被下游讀取;專案的提案機制不是這兩個 yaml 時,等價安放即可。但不可省略,省略時下游不會報錯,只會空跑通過。
移植前置條件
本 skill 是框架綁定的:它以框架資產的路徑為主題,依賴的基礎設施不隨它移動(同 version-bootstrap、ticket、doc,皆不宣告 portable)。搬進新專案前確認:
- 有具
blockedBy語意的 ticket 系統?步驟 4、5、6 全部依賴它 - 有提案機制(任何形式的持久文件)?步驟 3 的載體,也是版本啟動閘門的判定對象
- 有
multi-round-review?步驟 1 明示人工盤點會漏三類,無此 skill 時該風險由使用者承擔
缺項時進入降級模式,並記錄降級。 缺項與其後果記入該版提案的「阻擋清單」欄,並建一張補齊該基礎設施的票。缺 ticket 系統時不變量 3 無法成立(它要求綁 ticket),該版的待決管理退回無觀察者狀態,此事實須寫入阻擋清單。無降級記錄的使用不構成完成本流程。
Examples
待決按軸重排後阻擋消失(桌面文件視覺化專案):審查把待決從 5 項拓到 19 項,看起來全部擋在前面。按資料管線軸把每項綁到「它擋住的版本」後發現,前兩版(展示殼、來源判定 gate)完全不被任何待決擋住,可立刻開工;上游外部依賴只擋第三版之後。同一份清單,按文件來源看是 19 個阻擋,按管線看是兩個可動的版本。排序軸本身就是資訊。
gate 版的整合測試以真實環境為斷言(同專案):第二版的測試斷言是「本機全部真實專案各自進入正確的 gate 分支」,答案由實測得出(非框架專案 N 個/無型別表 M 個/可載入 K 個)。這類斷言沒有省力路徑,數字是外部固定值,改錯即紅。
切分軸失效而須重排(不變量 2 的適用上限,同專案):四層鏈 PROP→SPEC→UC→Ticket 按資料管線軸排版本,實作到第三跳時發現 UC→Ticket 在上游的 16 條語意邊中無對應邊,管線的某一段根本不存在。這推翻的不是某一版的內容,是版本之間的依賴,因此重排序列而非開小版本。
Common Issues
| 症狀 | 原因 | 處置 |
|---|---|---|
| 待決清單越長越不敢開工 | 把序列當閘門,以為要先清空 | 逐項問「它擋住哪個版本的整合測試」。在現有序列涵蓋範圍內擋不住任何一版的就不是阻擋;若序列本身可能不完整,先回步驟 2 複查切分軸 |
| 這版做完了沒?收尾一再延後,或有人問「算完成了嗎」 | 完成定義不是整合測試,是感覺 | 回到不變量 1:沒有整合測試的版本不成立 |
| 實作中撞到一個問題,翻出待決清單發現三個月前就記過 | 待決無觀察者(違反不變量 3)。它的真實浮現形態是事故,不是有人定期翻清單 | 逐項補 blockedBy 綁定;綁不到任何版本的二者擇一:立刻決策,或自待決清單移除 |
| 首版開了十張票但互相卡死 | 地基與功能混在同一波 | 地基波先行;功能票 blockedBy 地基票,功能票之間儘量無相依 |
| 驗收全綠但功能其實沒做 | 驗收 oracle 在執行者手上;或資料來源缺席時反而更好過 | 驗收改為指名外部固定值;對「逐項標記」類驗收檢查空實作是否也能通過 |
檢查工具回報 [OK] 或「無問題」,但你不確定它有沒有讀到東西 |
「沒東西可檢查」與「檢查通過」在輸出上同形 | 確認被檢查的欄位或檔案非空;空集合的通過不是通過 |
| 同一段管線已經開了第三張小版本票 | 修的可能不是內容而是切分軸 | 由開該票的執行者觸發回步驟 2 複查切分軸(見不變量 2 的適用上限) |
版本紀錄在同目錄的 CHANGELOG.md。