跨模組路由要驗證目的地承接該主題、不只驗證目的地存在
論述基礎與限制
本卡從一次教材路由事故抽出。新寫的密碼學選型章節在 out-of-scope 列表寫「金鑰託管平台選型 → 05-deployment-platform」,把讀者送去部署平台模組。實際上該模組的 vendor 清單是 docker、kubernetes、nginx、envoy、traefik 這類部署工具,一個金鑰託管平台都沒有,也沒有相關章節;而該模組自己的 vendors/ 底下有一整組金鑰託管與機密管理服務頁(aws-kms、hashicorp-vault、google-cloud-kms、azure-key-vault 等)——它們全都在本章自己的模組底下。這條路由送出去的位置,離正確答案比原地還遠。
事故經過三輪、十個 reviewer 的多輪審查沒有被抓到,由使用者閱讀時提問「這篇文章不存在,還是列在 backlog」而浮現——問題的形態是第三種:路由指向了不承接該主題的模組,兩個直覺解釋都沒中。
限制:本卡談的是路由的目的地驗收,不是路由的條目寫法(條目自包含見 #204)、也不是引用錨點的穩定性(見 #155)。適用於任何「把讀者送去別處」的結構:章節的下一步路由、模組的交接欄位、卡片的鄰卡連結、文件的參見段。
核心原則
路由的驗收條件是「目的地實際承接這個主題」,不是「目的地存在」。 兩者的差距在於:存在性可以機械驗證(檔案在不在、連結能不能點),承接與否要語意判定(那個模組真的有這個主題的內容嗎)。多數檢查工具與審查習慣都停在前者,而讀者受傷的是後者——他點過去、翻完整個模組、發現沒有,然後不知道該回哪裡。
這裡有一個容易誤判的分岔。發現路由落空時,直覺的兩個解釋是「文章還沒寫」或「已經列在 backlog」,兩者都預設方向是對的、只是內容還沒到。但還有第三種:方向本身錯了,內容在別處、甚至就在讀者剛離開的那一頁底下。這一種最難察覺,因為路由條目本身讀起來完全合理——把金鑰託管歸給部署平台,在語感上並不突兀。
承接之上還有一道關卡:可達。目的地確實擁有這個主題,但它埋在某個小節的第三層時,讀者到站後的體驗與落空相同——他看到一整頁不相干的內容,判斷「應該是我找錯了」然後離開。驗收因此要走到落點的第一屏:從路由指過去之後不再往下捲、不再點第二次,看得到這個主題嗎。存在、承接、可達是三道遞進的關卡,機械檢查只驗第一道,語意審查通常停在第二道。
反模式:驗證停在存在性,於是沒有一層對它負責
失效鏈在來源端有三層,每一層各自都在正常運作,合起來卻沒有任何一層負責這件事。
工具層:連結檢查驗的是目標檔案存在。而模組級的路由常寫成 code 格式的模組名(`05-deployment-platform`)而非連結——它不是連結,所以連存在性檢查都不進。指涉一個不存在的模組都不會報錯,更不會有人問它承不承接該主題。
審查層:跨章一致性 frame 查的是「連結有沒有斷、錨點在不在」,outbound frame 查的是「既有內容該不該指向新內容」。兩個 frame 的方向都對,但都不問「這條既有的路由,目的地真的有這個主題嗎」。這是 #126 說的軸線缺口——這一軸沒有人在看,而非某一軸做得不夠深。
作者層:寫 out-of-scope 與交接路由時,分配依據是主題的語感歸屬(金鑰託管聽起來像基礎設施、基礎設施像部署平台),而不是去目的地確認過。寫作當下這個動作的成本很低——切過去看一眼就知道——但它不在任何檢查清單上,所以不會發生。
這三層都是來源端的視角。目的地端還有一層沒有人在看:被指向的那個模組的維護者,沒有機制讓他知道有哪些 inbound 路由指著自己。這一端的檢查成本其實最低——模組主人最清楚自己承不承接某個主題。
四層失明疊起來的結果是:路由錯誤可以存活過完整的審查流程,最後由讀者承擔。這與 #155 指出的「misdirected 比 dangling 更難偵測」是同一個機制在模組層的形態——成功解析到錯的地方,比解析失敗更難發現,因為前者沒有任何錯誤訊號。
修法:寫路由時反向確認,落空時分四種處置
寫的時候:每寫一條跨模組路由,去目的地找出承接該主題的具體檔案或段落。找得到就把路由指向它(能給連結就給連結,比指模組名精確);找不到就進入下面的處置分流。這個動作要在寫路由的當下做,因為當下正在想這個主題,判斷成本最低。
給不出連結時,條目要寫出剛才驗到的落點名稱(哪個檔案、哪一節),讓下一個人能複驗。只留模組名等於沒有留下驗證痕跡——去看過與沒去看過的產物完全相同,整條規則因此不可證偽。
落空時分四種處置,判準是「這個主題該不該由那個模組承接」:
- 指錯了:主題有內容、只是在別處。改指正確落點。這是最容易被誤判成「還沒寫」的一種,所以發現路由落空時第一步是全站搜一次該主題,確認它確實不存在,而不是直接假設要新寫。
- 該有但沒寫:方向正確、內容確實缺。列進目的地模組的 backlog,並在路由條目標明狀態,別讓讀者點過去撲空。接著判斷要不要先建簡版——判準是讀者到達後能不能拿到最小可行答案:如果一段話加幾個連結就能讓他繼續往下走,先建簡版比留空好,之後再補完整內容;如果這個主題需要完整推導才有價值,簡版會給錯誤的完成感,那就只留 backlog、路由條目暫時拿掉。登記時在前置條件欄註明是哪一篇路由指過來的,否則目的地模組無從知道有 inbound 路由押在這一項上。建了簡版的話該項仍留在 backlog 並標明現況是簡版——簡版讓路由不再落空,不代表主題已被承接,而路由不落空之後就沒有任何訊號會催它補完。
- 根本不該路由:這個主題不屬於任何現有模組、或它其實在本文的範圍內。刪掉該條,或收回本文處理。刪的前提是確認過它不屬於任何地方——只是暫時找不到落點時走 #212 的處置,標出建議目的地並登記待辦。刪除是這四種處置裡最省力的一種,而省力正是它會被誤選的原因。
- 目的地在自己維護的範圍之外:主題該由外部規格、官方文件或別人的知識庫承接。這一種的驗收條件與前三種不同,因為那個目的地會改版、改路徑、甚至下架,而自己沒有辦法讓它保持承接。處置是連過去的同時在條目裡寫明「到那裡要拿到什麼」,讓連結日後失效時讀者至少還知道自己該找什麼。反過來用:寫不出「要拿到什麼」的外部路由,通常是在推卸而不是在導引。
審查時:把「路由目的地承接驗證」列為一個獨立的檢查維度,逐條路由問「去那裡真的找得到嗎」,找得到的再問一次「到站的第一屏看得到嗎」。這一維不能靠連結檢查代勞,因為 code 格式的模組指涉不進工具的視野,而可達性連指得進去的連結也驗不了。
這一維的產出是一張逐條表(路由條目 / 目的地 / 實際承接的檔案或段落 / 到站第一屏看不看得到)。沒有列出條目的「已檢查」不成立——抽查三條與逐條驗完,在不列條目的報告裡長得一模一樣,而逐條驗的成本正是抽查的誘因所在。
Sibling 維度:需求最強的來源有沒有指過來
本卡驗的是 outbound——本文指出去的那條路由成不成立。反向的那一維同樣會 silent 失效:新內容寫完之後,最需要它的那些既有頁面有沒有指過來。
實測形態:四篇文章的審查揭露它們共用某個未承接的缺口,於是補了三章專門承接。三章寫完各自有三個以上的 inbound、orphan 檢查通過——而那四篇裡有三篇完全沒指向它們。四篇正是需求最強的入口(三章就是為了補它們的缺口而寫的),缺口卻留在那裡,因為寫新章時只寫了它自己的「下一步路由」(往外指),忘了往內指的那一半。
orphan 檢查對這種情形放行是必然的:它問的是「有沒有人指」,而這一維要問的是「該指的人有沒有指」。前者是數量門檻,後者要先答出「誰最需要這篇」。可操作的做法是新內容交付時列出它的需求來源清單(哪幾篇的讀者會需要它、各自在哪一段會產生這個需求),逐條回去補——而那份清單多半就是當初決定要寫這篇的理由。
跟其他原則的關係
- #155 引用章節用語意標題、不用位置編號:同一個失效機制(misdirected 比 dangling 難偵測)的不同層。#155 處理章節內的引用錨點會 silent 漂移,本卡處理跨模組的路由目的地會 silent 落空。兩者都是「成功解析到錯內容」沒有錯誤訊號。
- #204 路由條目要自包含:處理路由條目本身的可讀性(跳轉單位不依賴鄰條上下文),本卡處理路由指向的另一端是否成立。兩張卡合起來才是一條路由的完整驗收:條目讀得懂、目的地接得住。
- #232 自審 sweep 的偵測方法要對齊規則類型:本卡是它的具體實例。用「連結有效性」這個偵測方法去查「路由是否成立」這類規則,方法與規則類型不匹配——前者是機械可驗的存在性、後者是語意判定的承接關係,所以查了也抓不到。
- #126 寫作 review 是多軸完整性、不是單軸深度:補救是加一軸:完整的多輪審查沒抓到,是沒有任何一軸負責這件事,而非既有的軸做得不夠細。
- #244 範例讓最後一類出口缺口現形:本卡驗既有路由指得對不對,#244 驗該有路由的地方有沒有路由。一篇文章可以每條路由都通過本卡的三道關卡,而仍然在段落層級處處落空——兩者是同一件事的品質面與覆蓋面。
- #147 規範化跟自審是兩種認知任務:本卡把檢查維度寫進規範之後,同一批稿件的其他路由仍需另外掃一次——立規範的當下不保護已寫好的內容。
判讀徵兆
- 路由條目用 code 格式寫模組名(
`05-deployment-platform`)而非連結:這種形態逃過所有連結檢查。 - 寫路由時的依據是「這個主題聽起來屬於哪個模組」而不是「我去看過那個模組有這個內容」。
- 讀者回報「這篇文章不存在嗎」:這個提問的形態通常預設方向正確,實際要先驗證的是方向本身。
- 同一個主題的 vendor 頁或章節在 A 模組,而 A 模組自己的路由把該主題送去 B 模組——路由送出去的位置比原地還遠。
- 模組的 out-of-scope 列表比它的實際交接關係長:宣告了很多「這不歸我管」,但沒確認過歸誰管。
- 路由指向一個很大的目的地(整個模組、整篇長文),而該主題在那裡只佔一小節:連結有效、主題也在,讀者到站後仍然要自己找。
- 判讀表的 N 列裡只有 M 列有對應的深化段:欄位齊全會遮住這個不對稱,而缺的那幾列等於認出自己之後沒有地方可去。