M13:diff 壓縮,與測試斷言子字串碰撞
unified/git diff 的結構清楚:context 行(空格開頭)提供可讀性但不含變更資訊;
hunk header(@@)和 +/- 行才是關鍵。
M13 把未變更的 context 行丟掉,保 hunk header、檔頭(diff/index/---/+++)、所有變更行。
測試:07_diff.json 從 7227 bytes 壓到 1857,Python 和 Rust 逐字節一致。
這片留下一個 marker naming 的陷阱。末尾標記寫的是
dropped N diff context lines | sha256:key,
而測試斷言用了 "context line" not in out 驗「context 行被丟掉了」——
結果 marker 文字本身也含 "context lines",測試誤觸。
解法是改查 "unchanged"(context 行的語義詞),不查 marker 文字裡的用詞。
marker 用詞和測試斷言必須避開子字串重疊。
嗅探守門加了兩條防呆:輸入必須含真 @@ hunk header(排除 markdown 的 +/- 條列)、
且 context 行比例至少 30%(全是變更行的 diff 根本沒噪音可丟)。
M14:用「路徑含 /」分辨 grep 和 log timestamp
grep/rg 輸出格式是 file:lineno:content。
最直覺的解析法是「冒號分隔、第二欄全數字就是行號」。
這個方法在 log 時間戳上會掛掉:2026-06-20T10:30:45 字面就是「欄:數字:欄」,
search 策略會誤認為 grep 結果,把 M12 log 策略的輸入截走,推翻已經驗過的行為。
解法:要求第一個 : 前的 file_key 含 /。
真實的 grep -rn pat . 路徑必帶斜線;時間戳前綴 2026-06-20T10 不含斜線。
純 ASCII byte 檢查("/" in key),Python 和 Rust 完全一致,不踩 unicode 分岔。
08_search.json:4289→1702 bytes。
test_search_does_not_swallow_logs 是鎖定測試:確保既有的 log fixture(不含 / 的行)
在加了 search 策略後仍走 LOG 路徑、不回歸。
M13/M14/M15 三片零回歸,dispatcher 五片都通。
M15:為什麼 byte-level 照抄比對齊 encoder 更穩
M15 壓法:找元素最多的 array,保前 5 + 後 2 個元素、中間塞 marker 字串元素,array 外 bytes 照抄。 起初實作路線是 parse→截斷元素→重序列化,結果 parity 測試掛掉。
根因是數字正規化分岔。Python json.dumps 把 1.10 正規化成 1.1;
Rust serde_json 開 arbitrary_precision 後保留 1.10。
同一份 fixture 含 1.10,兩側序列化結果不同,parity 破掉。
對齊 encoder 可以補,但要在所有 edge case 上各自維護兩個語言的序列化設定——沒有根本解決問題。
換一個出發點:根本不重序列化任何值。
byte-level 結構掃描追蹤字串字面值(讓字串內的括號不算巢狀深度)、追蹤深度(讓逗號只切最內層),
記錄每個元素的 byte span,被保留的元素直接照抄原始 byte 切片。
唯一新寫入的只有結構字元 [ , ] 和 marker(全 ASCII 常數)。
這些是跨語言不可能分岔的東西。
09_json.json 刻意含 1.10 和 1e10:2959→1651 bytes,數字原樣保留,逐字節一致——
正是「照抄不重序列化」拆掉地雷的直接證明。
這片還踩到一個 tie-break 坑:找元素最多 array 時同票,
Python max() 保第一個、Rust max_by_key() 保最後一個。
兩邊都改成「嚴格大於才替換」,行為對齊。
這個 session 前後踩了三個跨語言內建語意分岔:strip vs trim(unicode 空白)、
max 同票取捨、json.dumps 數字正規化。對策每次都一樣——改用顯式、ASCII-only、
byte-level 的確定性邏輯,不依賴語言內建的隱性語意。
三片連推,dispatcher 架構是主要原因
M11 建的 strategy dispatcher 讓加新策略只需動 strategies.py 和 strategies.rs:
各寫一對 (applies, squeeze)、插進 STRATEGIES 清單(TRUNCATE catch-all 之前)。
compress_block 泛型呼叫端從不改動。
M13/M14/M15 三片都是這個模式,零改造成本——M11 的設計連續第三、四、五度兌現。
最終狀態:dispatcher 五片(JSON、DIFF、SEARCH、LOG、TRUNCATE); Python 59→94 tests、Rust 72→101 tests、parity 6→9 fixtures、clippy 0; 6 個 commit 全推 fork,origin 停在 d77265c。
關鍵教訓
marker 用詞不能和測試斷言共用子字串:M13 marker 含 "context lines"、測試查 "context line" not in out——誤觸。改查語義詞("unchanged")而非 marker 文字本身。
分隔格式的辨識需要結構性守門條件:「冒號分隔第二欄是數字」不足以分辨 grep 和 log timestamp。要求 file_key 含 /——這是 grep 路徑的結構性特徵,timestamp 沒有。
JSON parity 的正解是照抄不重序列化:parse→重序列化一定踩語言內建的數字正規化分岔。byte-level 切片把地雷根本移走,比對齊兩個語言的 encoder 更穩。
跨語言內建語意每次都要顯式對齊:strip vs trim、max 同票取捨、json.dumps 數字正規化——三個坑。對策一律是改用顯式、ASCII-only、byte-level 的確定性邏輯。
dispatcher 骨架的報酬在第三片後才完全看見:一片策略時「只動兩個檔案」感覺平常,三片連推時「三片零改造成本、零回歸」才是這個設計的真實報酬。