代理比本體便宜,所以成本壓力最高的階段一定伸手拿代理
論述基礎與限制
本卡從一個工作階段的四個實例歸納,其中三個是自陳、一個由併行的另一個階段提供。四個都出自同一段連續的工作,所以「這個機制在別的階段多常發生」沒有量測;成立的是它們共用同一個結構,而不是它的頻率。修法方向(降低本體的取用成本)尚未實測。
核心原則
檢查一件事的時候,手邊通常有兩個東西:本體,與一個站在它前面的代理。 規則的 regex 是本體,錯誤訊息對它的描述是代理;自己跑一次是本體,別人量過的那個數字是代理;成品的全部是本體,這一輪改動過的檔是代理;不加豁免時會失敗的位置是本體,自己寫的豁免條款是代理。
代理比本體便宜,而且它們的產物在報告上同形。 兩條路徑走完都得到一個零、一次通過、一句「已檢查」。
收尾階段的成本壓力最高,所以在那個結構下伸手拿代理是理性的。 這一句是本卡的重點:「下次更仔細一點」對它無效,因為問題不在注意力的總量,在那個時點的成本結構剛好指向代理。
四個實例的差價都很小
| 代理 | 本體 | 差價 |
|---|---|---|
| 錯誤訊息的描述 | 規則的 regex | 打開一個檔 |
| 別人量過的數字 | 自己跑一次那條指令 | 一條指令 |
| 這一輪改動過的檔 | 成品的全部 | 改一個路徑參數 |
| 自己寫的豁免條款 | 不加豁免時會失敗的那些位置 | 跑一次不帶豁免的版 |
每一個差價都小到「就用代理吧」不像一個決定。 這是它難防的地方——沒有一個時刻可以指認為「我在這裡選擇了走捷徑」,於是事後回看也找不到那個決定點。
套用之前先驗那個差價是真的
本卡的三條修法都預設「代理確實比較便宜」,而那個前提要驗過才算數。打開一個檔、跑一條指令這類差價是真的,看得見也算得出來;有些看起來像成本的東西一量就翻轉——審查只問效力不問代價裡的「找誤報會減少產出」就是一例,實測顯示撤回換來的是更準的 finding,那個成本差並不存在。
「這是理性的成本選擇」是一個可以被驗的宣稱,不是一個解釋。 沒驗就套用它,等於把一個未經檢驗的假設寫成了經濟學,而它會讓一個該修的偏斜看起來合理。
修法:改成本結構,不改注意力
降低本體的取用成本。 把 regex 印進錯誤訊息、把「自己跑一次」做成一行可複製的指令、給檢查器一個「不帶豁免」的旗標。差價降到零,代理就沒有優勢。
讓兩者的產物長得不一樣。 回報要附「這個結論來自本體還是代理」——查核責任的五欄分類與零命中的兩軸做的正是這件事,它們把同形的產物拆開。
在收尾清單上明列這一項。 每一步旁邊寫「我用的是本體還是代理」。這一條的作用是把那個不像決定的動作變成一個要填的欄位。
條文自帶量測指令時,那條指令就是條文的代理
規則附一條可以直接跑的指令是好事,而那條指令量的東西與條文說的東西可以不是同一個,兩邊各自都正確,於是沒有訊號。讀的人拿到的是指令,因為指令跑得出結果而條文跑不出。
一次針對本站裝飾符號規則的掃描把這件事的三層都攤開了。條文寫的是全稱——正文不可用 emoji 與裝飾性 unicode,括號裡舉了幾個例並帶「等」字。附的指令是一串固定的符號列舉,於是清單外的符號合規地通過。第二層是同一條規則在兩份文件上附了兩條長度不同的指令:規範入口那一份列十個,被指定為單一真實來源的那一份列二十二個,而讀者拿到哪一條由他打開哪一份決定。第三層是兩份列舉都漏掉內容庫裡實際在用的一個符號——它被當成標題前綴與項目符號,正是條文要禁的用法,而兩條指令都掃不到它。
同一批還有一個更小的實例:一份 skill 的規模門檻寫「SKILL.md body 保持在某個行數以下」,而它同一節給的量測指令是 wc -l 全檔,差一個 frontmatter。門檻寬鬆時這個差無關緊要,而條文與它自己的指令量的確實是兩個東西。
所以規則附指令時多兩個驗收。把條文的名詞與指令的輸出並排,問它們是不是同一個集合——不是的話二選一:改條文去對齊指令(承認實際管的就是這個),或改指令去對齊條文(多半要換成另一種形態,例如把列舉換成範圍)。再問這條規則在幾個地方附了指令——超過一個就要逐份比對,因為列舉型的指令會各自增長,而增長不會同步。
第二個機制:代理與本體在觀察者的位置上重合
價差解釋了大部分的實例,而有一類的代理不是因為便宜才被取——是因為觀察者站的位置讓代理與本體看起來是同一件事。一次外部自陳給了兩個同形的實例:一個回報者兩次把本地狀態當成遠端狀態(一次是版本號、一次是某個檔有沒有被刪),兩次都查證過本地那一側而從未查刪除端或發佈端。他自己的歸納是「查了容易查的那一側,而結論依賴的是沒查的那一側」。
這一類與價差型的差別在有沒有那個決定點。價差型事後回看找不到決定點,因為差價小到伸手拿代理不像一個決定;位置重合型連決定都沒有發生過——看得到的那一側就是「我知道的全部」,另一側在意識裡不存在,所以沒有東西被略過。
位置重合型的第三個實例把「位置」這個詞說得更準:一條用 git log 判定檔案來歷的指令,對一個一直在磁碟上、只是被 .gitignore 排除的檔回報「從未擁有」——它繼承了 tracked 樹這個視角,而 git 是最順手的歷史來源,於是「git 知道的」就成了「發生過的全部」。這一次的代理是自己拿的,不是工具替他拿的,而且拿的人是剛把那條指令寫進規則的人。
這一類還有一個更被動的形態:代理由工具的措辭預先包裝好。一支刪除工具把「只存在於遠端」的檔案標成「本地已刪除但遠端殘留」,成因就寫在標籤裡,於是讀的人連問一句的機會都沒有。**取代理的動作發生在工具那一端,讀的人只是接受了結果。**判別因此要往前挪一步:讀到一個把成因寫進去的分類標籤時,先問這個成因是誰認定的。
處置因此也不同:價差型改成本結構(降低本體的取用成本、讓兩者的產物長得不一樣),位置重合型要改的是問句的形式。把「我確認過了」換成一個會暴露位置的問句——支持這句話的指令跑在誰的機器上、這個狀態存在誰那一端、我讀的是自己的紀錄還是狀態所在的那一份。答案裡出現「我的」「本地」「我的紀錄」,就是還沒查另一側。
一個新的實例把這個機制推到最遠:查一份共用資產在發佈端的實際內容時,讀它的原始檔案端點。那個端點與來源在「讀得到內容」這個位置上重合,取用它與成本差無關——它就是手邊那個入口。而它有內容分發快取,回讀到的是數分鐘前的狀態,落差沒有任何訊號:讀得到、格式正確、看起來就是答案。一次實測據此判定「推上去的內容被覆蓋」而做了一輪重寫,那輪重寫反而蓋掉對方已經寫好的修正;實際狀態要取完整歷史(git clone)才拿得到。這一例的形態比本節既有的幾個更難察覺,因為前面那幾個(本地代理遠端、git 代理磁碟)至少換了一個名詞,而這裡代理與本體連名字都相同。完整事件見 #340 版號擋不住並行覆蓋。
跟其他原則的關係
要交出物件,不要交出關於物件的判斷 — 本卡在追問端的形態,而那一張的「物件」與「關於物件的判斷」就是本體與代理。兩者的關係是本卡給成因、那一張給動作。
「我以為觀測到的」躲在「引用的」那一欄裡 — 那一張的第五欄(別人量的、我引用)是本卡在數字來源上的具體化,而它的五欄分類是本卡第二條修法的實作。
掃描的作用域會默默對齊「我這次動過什麼」 — 那一張的改動集合是成品全集的代理,而它指出的成因(手邊那份清單在別的用途上正是對的作用域)是本卡差價很小的一個實例。
已經記錄過的失效仍然重演 — 相鄰而軸不同。那一張問防線放在哪裡(要人先起疑才會打開),本卡問走到防線要花多少錢。兩者合起來解釋「知道」為什麼不等於「做到」:一個是觸發不到,一個是觸發到了而代理更便宜。
#347 審查的產出是判定還是歸因要先宣告 — 反方向的同一個要求。本卡要求套用「這是理性的成本選擇」之前先驗那個價差存不存在;那張卡的歸因成本確實存在而且很大,卻同樣沒有被算過,因為它從來沒有被表述成一個選擇。兩張合起來是完整的:沒算過的價差有兩種,一種其實不存在,一種大到不該默默付。
#348 規範文字的效力由它在讀者程序裡的位置決定 — 本卡的機制在讀規範這件事上的形態:讀者在判定表內取到可填的值就停止,表外的診斷段落不被當作取值來源——表格是代理、表外段落是本體。那張卡加的是位置這一側的處置,把本體搬進表格那一格之後差價就消失了。
判讀徵兆
- 同一個階段反覆出現表面不同的失效,而處置一律寫成「下次更仔細」。
- 某個檢查的產物是一個零或一句「已檢查」,而說不出它是從哪一條路徑得到的。
- 一件事有兩個可用的來源,而兩者的差價是一條指令或一個檔案。
- 事後回看找不到「決定走捷徑」的那個時點。