引用章節用語意標題、不用位置編號:編號是結構排列的 derivation、會隨版本漂移
結論
跨段落、跨檔引用一個結構單位(章節、階段、條列項、輪次)時、引用它的語意標題、不引用它的位置編號。「見核心問題」「在操作盤點階段確認」是穩定引用;「見 Stage 3」「Stage 1-3 出現訊號時」是把當下的排列順序寫死進引用點。
編號可以存在、但只承擔兩個角色:當下閱讀的排序導覽(條列 1、2、3)、跟發布方凍結過的外部 contract(RFC 段號、法條條號)。活文件(會演進的規範、skill、教材、設計文件)的編號是結構排列的 derivation — 插入一個新章節、所有後續編號全部位移、散落各處的引用點卻不會跟著動。
這條原則同時定義了標題的責任:每個結構單位都要有說明核心意義的語意標題、讓引用有東西可錨。只有編號沒有語意標題的章節(「Stage 3」「第五章」)、等於強迫所有引用者使用會漂移的錨點。
為什麼編號引用會 silent 失效
編號是 derivation、引用是複本
一個章節的編號由「它前面有幾個章節」決定 — 這是排列的衍生值、不是這個章節自身的事實。把「Stage 3」寫進另一個檔案的引用句、等於把這個 derivation 的快照複製出去當 fact 用;結構一變、所有快照同時過期、而且沒有任何機制通知它們過期了。
失效模式比 broken link 更糟:misdirected、不是 dangling
| 失效類型 | 觸發 | 偵測難度 |
|---|---|---|
| Broken link(dangling) | 目標消失 | 工具可掃:link checker 直接報 404 |
| 編號錯位(misdirected) | 目標位移、編號被新內容占據 | 工具掃不出來:「Stage 3」字面依然存在、只是指向了別的階段 |
連結斷掉會報錯;編號錯位會成功解析到錯的內容。讀者照著「見 Stage 3」翻過去、看到的是一個真實存在、語意卻完全不同的階段 — 他沒有任何訊號知道引用已經過期。修復也只能靠人工逐處判讀:grep 找得到所有「Stage」字面、但無法判斷哪些語意還對、哪些已經錯位。
語意標題也會改名 — 兩種斷裂不同級
語意錨的最強反例是「標題也會改名、改名後所有語意引用一樣過期」。這個攻擊成立一半 — 引用確實會過期、但斷裂的型態與偵測條件完全不同。改名讓舊引用斷成 dangling:「見核心問題」找不到目標、grep 與讀者都判得出引用過期了;編號位移斷成 misdirected:成功解析到錯的內容、無人察覺。更關鍵的差異是操作者在場與否 — 改名是對目標單位的顯式操作、改名者當下就知道該掃引用面、修復可以發生在同一個 commit;編號位移是別處插入章節的副作用、被位移的章節沒有人碰過、它的引用過期沒有任何人在場負責。語意錨輸在「也會變」、贏在「變的時候可偵測、有人在場」。
時間維度的累積
寫下引用的當下、編號跟語意完全對得上 — 這正是這個反模式難以自察的原因。漂移發生在後續版本:插入新階段、合併兩章、把一節搬到另一個檔案。文件越活躍、引用點越多、每次重排的人工修復面就越大;漏修一處、就埋下一個 misdirected 引用等讀者踩。
反模式與修法
| 反模式 | 修法 |
|---|---|
| 「見 Stage 3」「進 Stage 4 前確認」 | 「見核心問題」「進維度展開前確認」— 用階段的語意名稱 |
| 「如第 3 點所述」「上述 1-3」 | 重述該點的語意:「如『底線告知協議』所述」「上述三個收斂判準」 |
| 「詳見第五章」(活文件) | 「詳見『防護底線清單』章」— 標題即錨點 |
| 章節只有編號、沒有語意標題(「## Stage 3」) | 編號與語意並列(「## Stage 3:核心問題」)、引用時取語意半邊 |
| 條列項被遠處引用(「套用流程的步驟 2」) | 給該步驟一個名字、或引用時帶語意(「套用流程的『抽 findings』步」) |
寫作時的判斷次序:先給結構單位一個承載核心意義的標題(這是標題的本職)、編號只作當下排序;引用時一律取語意名稱;引用點離目標越遠(跨檔、跨 surface)、越是只能用語意錨。
邊界:凍結編號是 fact、可以引用
發布方承諾編號不變的外部規格、編號本身就是 contract:RFC 的 section number、法條的條號、含版本年份的 ISO 條款(如 ISO 9001:2015 — 跨版改版會重編條款、引用時鎖定版本才算凍結)、已出版書籍的章節。這些編號被凍結成 fact、引用它們反而比引用標題穩定(標題可能在翻譯與再版間變動)。內部活文件想獲得同樣性質、要先付出同樣代價:宣告編號凍結、只加不改 — 多數活文件不值得也做不到、所以預設走語意引用。
跟其他抽象層原則的關係
- #156 集合命名用角色、不內嵌數量:命名端 sibling。本卡假設語意標題是穩定 fact、#156 負責讓這個假設成立 — 「核心七問」這種 count-bearing 標題一半是語意、一半是成員數的 derivation、引用端怎麼修都錨在會漂移的字串上。本卡初版的正面範例就用了「見核心七問」而未察覺、由 #156 抓出 — 兩卡是不同認知層的檢查、單獨跑任一個抓不到另一個的違規。
- #44 Single Source of Truth:本卡是 SSoT 在「結構引用」維度的實例。編號是位置的 derivation;把編號寫進多處引用點、等於把 derivation 當 fact 散寫多份複本 — fact(章節的語意身分)只在標題一處、引用就該錨在那裡。
- #93 URL slug 必須顯式定義為 fact:同屬「引用要錨在 fact」家族。#93 把跨工具 identifier 從推導值升級成顯式 fact;本卡把跨段落引用的錨點從位置推導值(編號)換成語意 fact(標題)。兩卡的失效模式同型:推導鏈分歧、silent 失效、compile / lint 階段看不出來。
- #84 Naming 是 iterated artifact:標題是名字。本卡要求標題承載可被引用的語意、等於對標題套用 #84 的 cross-call-site 檢驗 — 從引用者的角度看、這個標題單獨出現時讀者知道它指什麼嗎?只有編號的標題在這個檢驗下直接不及格。
- #97 Metadata surface 要納入寫作 review 範圍:引用句屬於 #97 分類中的 navigation surface(跟 link label、索引條目同層)— 同樣是正文之外、卻直接決定讀者入口正確性的層。重排結構時、review 範圍要把散落各檔的引用句列入掃描面、而不是只改目標檔。
觸發 case
設計一個多階段訪談 skill 時、初版流程四階段、各檔用「Stage 1 的核心七問」「Stage 3 收斂時」互相引用。下一版把流程改成六階段:操作盤點與領域切分插入在前、核心七問從 Stage 1 變成 Stage 3、決策收斂從 Stage 3 變成 Stage 5。
後果具體呈現了上述失效模式:十多處跨檔引用要修、grep「Stage」找得到所有字面、但每一處都要人工判讀語意 — 「Stage 3 收斂時」字面完好、語意卻已指向錯誤階段(舊 Stage 3 是收斂、新 Stage 3 是核心七問)。實際修復中就有兩處漏網、靠第二輪全 repo 掃描才補上。若初版引用寫的是「核心問題」「決策收斂階段」這類語意名稱、這次重排的引用修復成本是零。
判讀徵兆
- 寫出「見 Stage N」「如第 N 點」「上一章提過」「§N」且目標是活文件時 — 改用語意標題引用。
- 章節標題只有編號或編號加泛稱(「階段三」「Part 2」)— 補語意半邊、否則其他文件只能用編號引用該章節。
- Review 掃描可用:
rg "Stage [0-9]|第 ?[一二三四五六七八九十0-9]+ ?(章|節|點|步|輪)|§[0-9]"— 命中是候選、要逐處判讀目標是凍結編號還是活文件。 - 結構重排(插入 / 合併 / 搬移章節)的 commit、檢查清單要包含「全 repo 掃引用句」、不是只改目標檔。