以對象起手的句子:缺少的動作者、時機與觸發原因,審查修正寫出這類句子的成因與偵測方式
「一個檔案被幾個不同的需求修改過,可以從版本歷史數出來,這個數字決定哪些檔案值得回頭讀修改紀錄」主詞、謂語、受詞都在,讀起來通順,而讀者讀完說不出三件事:數的人是誰、他在工作流程的哪一步會去數、為什麼他需要這個數字。句子以被討論的對象(一個檔案)起手,用被動句把動作者藏起來,再讓指標(這個數字)當「決定」的主詞,做決定的人從句子裡消失了。
讀者讀一句描述做法的句子時,要拿到的是 5W1H 裡的誰(動作者)、什麼時機(工作流程裡碰到這件事的那一刻)、做什麼、為什麼會觸發。正常的順序是先寫誰在什麼時機做了什麼,再寫他看到什麼、為什麼要這樣做:「工程師做 code review、查看一個檔案的修改紀錄時,從版本歷史發現它被幾個不同的需求修改過」。判斷問句是:這一句描述的事,誰做、在工作流程的哪一步做、為什麼會發生,能不能從這一句、前一句或所在段落的第一句逐字指出來。
失效的形態
一篇講「從修改紀錄判斷檔案要不要拆」的教材裡,使用者指出四句:
一個檔案同時對上兩列時,依每次修改的寫入者是人還是工具來分
工具產生的檔案由工具改寫,沒有人帶著意圖編輯,不屬於任何一種職責,處置是從統計排除、衝突靠重新產生
commit 數會把同一個需求的多次 commit 各算一次、也偏向常被順手修改的大檔案,所以這份清單只用來挑要讀哪幾個檔案的修改紀錄
一個檔案被幾個不同的需求修改過,可以從版本歷史數出來,這個數字決定……
四句各缺不同的格,形態有三種:
- 條件句起手、後面接沒有主詞的祈使:「一個檔案同時對上兩列時,依……來分」。「時」看起來交代了時機,而它寫的是檔案的狀態,不是讀者工作流程裡的一步;「分」是誰分,句子沒寫。讀者讀到這一句時手上有一張表,他要知道的是「我在對照這張表的時候,會碰到這種檔案,那時我該怎麼做」。
- 被動句把動作者藏起來:「工具產生的檔案由工具改寫」「一個檔案被幾個不同的需求修改過」。前一句的改寫有動作者(工具),而句子真正要交代的是後面的處置——誰從統計排除它、兩個分支衝突時誰重新產生它——那兩個動作沒有主詞。
- 指標當主詞:「這個數字決定哪些檔案值得回頭讀」「commit 數會把……各算一次」。數字與清單不做決定,做決定的是讀排行的人;把指標寫成主詞,讀者就分不清這一句是在描述工具的行為,還是在告訴他該怎麼用工具的輸出。
改寫後,每一句都由動作者與時機開頭:
讀排行的人對照這張表時,有些檔案同時符合兩種類型……兩種類型的處置不同,所以他依每次修改的寫入者是人還是工具,把這個檔案的修改分到兩種類型
這條指令數的是每個檔案被幾個 commit 改過:同一個需求分成多次 commit 時每次各算一次……讀排行的人只拿這份清單挑出要讀修改紀錄的檔案
改寫用的動作者都是文章本來就有的角色——讀排行的人、逐個 commit 歸類的人、解衝突的人、開發者——不必另外造。
這類句子是審查修正寫出來的
主 session 修完這幾句之後,用 git log -S 查每一句是哪一個 commit 加進去的:使用者指出的四句全部由多輪審查的修正 commit 加入(這一篇的 Round 1 一句、Round 3 兩句,這一篇還在 Python 模組時那一輪審查的 Round 4 一句);同篇另一句同形態的「常見的拆檔門檻是行數」來自初稿。
審查修正寫出這類句子有一個結構上的成因。審查意見本身帶著脈絡:steelman 那一輪問「一個檔案同時符合兩種熱點類型時怎麼辦」「commit 完全不帶需求編號時怎麼辦」,修正的人讀過那條意見,誰在什麼時機會碰到這個情形對他是已知的,所以他只寫答案,把問題的主語(那個檔案、那份清單)放在句首接著寫處置。讀者沒有讀過那條審查意見,拿到的是一句沒有問題的答案。
這與 #366 記下的現象同向:那一次改寫的人剛修完名詞缺所屬,下一句就寫出同一類;這一次主 session 收到使用者的指認之後,第一版的範圍交代寫成「範圍從以版本歷史數出每個檔案被幾個不同的需求修改開始」,同樣沒有寫是誰在數,第二次改寫才補上「用腳本讀 git 歷史」。
為什麼四槽位標準沒擋住
#358 的四個槽位裡有動作者一格,而這四句逐格查下來每一格都填了名詞:
- 被動句與「由……」句有動作者的位置,只是填的是次要動作的動作者(「由工具改寫」),主要動作(排除、重新產生)的動作者槽位不存在於句子裡,檢查者找不到一個空著的格。
- 指標當主詞時,動作者那一格填了名詞(「這個數字」),格子不是空的;四槽位檢查受詞是否在領域裡,沒有檢查主詞能否做這個動作。
- 時機與觸發原因不是四槽位的成員。條件句起手的「X 時」看起來填了時機,而它寫的是對象的狀態;四槽位裡沒有一格要求它是讀者工作流程裡的一步。
所以這一類需要兩件事:動作者那一格要問「主詞能不能做這個動作」(數字不能決定、清單不能挑選),以及多兩格——時機(工作流程裡的哪一步)與觸發原因(為什麼會發生)。
偵測:量過的兩種做法
逐字引出動作者、時機與原因的探針。 一組十七句的校準集,取自那篇教材改寫前的七句、主 session 改寫後的七句,與同篇三句原本就寫出動作者與時機的句子,打亂、不標示。三份 Haiku 指令逐字相同,每一句單獨給、沒有上下文,要它逐字引出「誰」「時機」「原因」,引不出就寫引不出。
判定規則是「誰」引不出,或引出的是指標、清單這類不能做動作的名詞(這個數字、commit 數、這份清單),三份裡至少兩份如此就標記。改寫前的七句標記五句;改寫後的七句與原本合規的三句共十句,標記一句,是範圍交代句(「本篇的範圍從……開始」,探針把「本篇的範圍」當成主詞),範圍交代句沒有在描述動作,判為誤報。
漏掉的兩句有同一個原因:句子前半有正當的動作者,缺口在後半。「工具產生的檔案由工具改寫……處置是從統計排除」的探針答「工具」,而缺動作者的是「排除」;「需求數是篩選訊號:腳本數的是不同的需求……它決定要不要回頭讀」的探針答「腳本」,而缺動作者的是「決定」。探針被要求只回答主要動作,所以一句有好幾個動作時它挑了有主詞的那一個。後來改成逐個動詞引出動作者,在整篇文章上跑的結果記在本節最後。
「時機」那一欄也有鑑別力:改寫前有兩句三份全數引不出時機(「這個數字決定」「commit 數會把」),改寫後沒有一句引不出。「原因」那一欄沒有鑑別力:探針會把句子裡任何一個子句當成原因填進去,改寫前後的句子都填得出一個子句。
關鍵詞找候選。 在改寫前的整篇(去掉程式碼區塊,一百六十句)跑三條 pattern:指標接「決定」((這個數字|需求數|commit 數|它)[^。,]{0,4}決定,排除前面是「用」「拿」「依」的)命中兩句,兩句都是違規;句首名詞接被動(被|由 接「修改、改寫、寫入、產生」)命中五句,兩句違規、兩句在已刪除的練習題裡、一句是祈使句(「比較拆出來的各個新檔被幾個需求修改」,誰比較沒寫,可以算違規);條件句接沒有主詞的祈使(X 時,依|照|先|把)命中三句,一句違規、一句是「依賴單向時」的誤命中、一句(「某個新檔很快又成為熱點時,把它的修改再歸類一次」)缺動作者。三條 pattern 只能縮小要讀的範圍,「常見的拆檔門檻是行數」這種沒有被動也沒有條件句的形態,三條都抓不到。
逐個動詞引出的版本在整篇文章上跑過一次。 改完被指出的句子之後,主 session 把同一篇教材的全文 214 句散文分成三批,每批派三份 Haiku,指令改成列出每一個描述動作的動詞、逐字引出它的動作者與時機。結果的雜訊很高:探針把「是」「屬於」「等價」這類描述狀態的動詞也列進去,沒寫主詞的祈使句一律回報引不出,幾乎每一句都有至少一個動詞被標記。這個版本只產出候選,主 session 判讀時再套兩條條件才收斂:
- 只看描述某人在工作流程裡做的動作(歸類、排除、加進、重跑、比較、判讀、列出、移到、檢查)。描述工具或機制自身行為的句子(git 的改名偵測決定衝突的形態、
--first-parent只走主線)、狀態動詞、定義句與解法陳述(「根本的解法是……」)不算。 - 這一句與所在段落的第一句都沒有寫出動作者才算。段落第一句已經寫出動作者時,同段後面的祈使句沿用它;要求每一句或每兩句重寫一次動作者,步驟說明會變得冗長,而讀者讀一段程序時手上有那一段開頭交代的角色。
至少兩份引不出、又通過兩條條件的共 37 句,主 session 全數補上動作者(讀排行的人、執行腳本的人、歸類的人、解衝突的人、開發者、團隊)後提交。三條關鍵詞 pattern 在同一篇扣掉重疊只命中 8 句,其餘候選來自探針。
修法
- 生成端:寫描述做法的句子、條件句與段落首句時,先填動作者、時機、做什麼、為什麼四格再成句。動作者要是能做這個動作的人、角色、工具或程式;指標與清單只能當受詞或被引用的依據(「讀排行的人用需求數決定」)。時機寫讀者工作流程裡的一步(「對照這張表時」「rebase 到拆分之後的版本時」),不寫對象的狀態(「一個檔案同時對上兩列時」)。
- 審查修正:把一條審查意見改進稿件時,先把那條意見帶給作者的脈絡——誰在什麼時機會碰到這個情形——寫進句子,再寫處置。修正句是這一類最常見的產地。
- 審查端:派逐字引出動作者與時機的探針,逐個動詞回答;至少兩份引不出動作者、或引出的動作者是指標的列為候選,再過兩條條件(只看工作流程裡的動作;這一句與所在段落的第一句都沒有動作者),通過的由主 session 逐條判讀改寫。三條關鍵詞 pattern 用來挑要先讀的段落。
論述基礎與限制
校準集十七句、三份探針,來自同一篇文章,正例與反例的標籤由主 session 判定,而改寫後的七句也是主 session 寫的,標籤與改寫出自同一個判斷,可能同向偏誤。「指出的四句都來自審查修正」來自一篇文章的 git log -S,其他文章的比例沒有量過。逐個動詞的版本只在一篇文章(214 句)上跑過,兩條篩選條件是那一次由主 session 訂的,沒有在另一篇文章上驗證;補上動作者的 37 句也沒有再派探針確認改寫後引得出。
跟其他抽象層原則的關係
- #358 技術文章的每一句寫清楚誰對什麼做了什麼事——那一張定義四個槽位;本卡補上動作者那一格的另一個檢查(主詞能不能做這個動作),並在四格之外加上時機與觸發原因兩格。被動句與指標當主詞讓四格查下來每一格都填了名詞,所以四槽位放行。
- #366 名詞要求的「誰的、什麼的」也是槽位——那一張的缺口在名詞的所屬,本卡的缺口在動作者與時機;兩者都是主詞謂語都在而讀者還原不出命題。逐字引出的探針做法沿用那一張的量測,改問不同的格。
- #355 教學定位被讀成教室講課——形態二「省略主詞與受詞」是最早的記錄;本卡是它在被動句、指標主詞與條件句三個形態上的延伸。
- #365 逐段審查量讀者學不學得會——審查者持有全文地圖所以解得開每個指稱;本卡記下的是修正者持有審查意見,所以他寫出的答案省略了只有那條意見才交代的問題。
- #374 「問題」與「回答」當框架詞——那一張是系統元件被寫成回答問題的一方;本卡是指標被寫成做決定的一方,兩者都把動作交給了不能做這個動作的主詞。
- #387 結構譬喻頂替主詞與動詞——限定本卡「誰做」那一問的適用邊界:「這條線處理的是……」的動作者那一格填了名詞,照本卡逐字找會找到「線」而放行;那張卡補上再問一次這個名詞是不是集合結構的譬喻、它做不做得了這個動作。
判讀徵兆
- 句子以被討論的對象起手(「一個檔案」「工具產生的檔案」「commit 數」),讀者讀完問得出「誰做的」「什麼時候」。
- 「X 時,依……」「X 時,把……」的 X 是對象的狀態,後面的動詞沒有主詞。
- 數字、指標、清單、排行當「決定」「挑」「判斷」的主詞。
- 審查修正 commit 加進來的句子,讀起來像一條條文,前後兩句沒有交代它回應的是什麼情形。
Case
2026-10-19,design-principles 模組〈從修改紀錄畫模組邊界〉。使用者先指出開場第一句是廢話,接著指出另外三句與它有同一個文法問題:討論一件事時通常會問 5W1H,這幾句缺少主詞、觸發的時間與為什麼會觸發;如果真的要寫導言,應該是「當工程師 code review 查看檔案的編輯紀錄,可以從版本歷史發現被幾個不同的需求修改過」,順序是誰做了、做了什麼、什麼時機點。使用者並指出這是 LLM 生成句子最常見的問題之一,要能辨識資訊不足的句子並用正確的順序寫。