Problem
#118 把 decode_deterministic 從封閉的 Bool? 換成 String-backed enum ——wire domain 因此
從封閉變成開放 (任意字串),而 decoding 仍是嚴格的。後果:
未來新增第 4 個 enum 值,對任何仍在讀同一份 store 的舊 client 是 breaking change,而且它
會靜默失敗。
為什麼是靜默的(#130 verify 的 DA-1,五個 leg 中只有 DA 抓到)
兩個消費端都把「大聲的 throw」轉成「安靜的 drop」:
路徑
行為
BenchmarkStore.load()
逐行 do/catch,壞 row → warnings.append("skipped malformed row")
SubmissionPackager.publishedKeys
用 try? → 完全無聲
而關鍵在於:BenchmarkStore.Snapshot.warnings 有零個非測試讀取者 。
grep -rc warnings Sources/bestasr/ 在整個 CLI target 零命中 ;每個 load() 呼叫端都丟棄它
(loadRecords() 直接串到 .projectedRecords();bench submit 只用 .measurements /
.machines)。唯一的讀者是 BenchmarkStoreTests 的四個斷言,註解還寫著 // still loud。
所以「loud degradation」目前只存在於單元測試裡。使用者兩條路徑都看不到任何東西。
而且掉一筆 row 不會留下空缺(DA-2)
latestMeasurements 是 append-only 檔案上的 latest-wins。實測:231 個 key 裡有 30 個有
supersession 歷史 (其中一個有 18 筆)。掉掉最新那筆的效果是靜默把已被取代的舊值升為現值
——對 #118 這種「未來新值會寫在最新 row 上」的變更,這是最壞的形狀。
Type
bug
Expected
至少其一:
identity-only decode struct (DA 判為正解,約 8 行):publishedKeys 只需要
modelId|corpusId|machineId|measuredAt 就能算 dedupe key,不需要解出整個 MeasurementRow。
用一個只含這四個欄位的 Decodable struct 讀,未知的 provenance 值就不會讓整筆 row 消失。
Snapshot.warnings 至少有一個生產讀取者(CLI 印出來),讓降級真的可見。
若要保留嚴格 decoding,明文記錄「加 enum 值 = breaking change,需要 migration」。cluster: decode_deterministic 三值 enum + honest gate 抽 helper + CLI 值域 (#118, #120) #130 已在
DecodeDeterminism 的 doc comment 留下這個警告,但那只是文件、不是機制。
Impact
Sources/BestASRKit/Contribution/Sharing.swift(publishedKeys)、
Sources/BestASRKit/Store/BenchmarkStore.swift(warnings 的可見性)、
Sources/bestasr/(若要印 warning)。
為什麼是 follow-up 而非 #130 的 in-scope fix
DA 的 scope 判準:「這個 PR 可以修它自己寫的文字、它自己弄假的文字、以及它自己建立的檔案裡的
測試——不修它只是讓人看見的東西。」
try? 與 warnings-無人讀 都是先前既有 的缺陷(四張表都受影響),#130 只是讓它們更容易被
觸及。但 DA 也指出這個框架只對一半:publishedKeys 註解所記載的前提
(「CI-valid ⟹ locally decodable」)是被 #130 弄成假的 ——所以 #130 有責任在文件層標註,
機制層的修復則屬本 issue。
Source : surfaced during /idd-verify PR #130 — Devil's Advocate DA-1 + DA-2(五個 verify
leg 中唯一發現 warnings 無讀者的一個)。
Problem
#118 把
decode_deterministic從封閉的Bool?換成 String-backed enum——wire domain 因此從封閉變成開放(任意字串),而 decoding 仍是嚴格的。後果:
未來新增第 4 個 enum 值,對任何仍在讀同一份 store 的舊 client 是 breaking change,而且它
會靜默失敗。
為什麼是靜默的(#130 verify 的 DA-1,五個 leg 中只有 DA 抓到)
兩個消費端都把「大聲的 throw」轉成「安靜的 drop」:
BenchmarkStore.load()do/catch,壞 row →warnings.append("skipped malformed row")SubmissionPackager.publishedKeystry?→ 完全無聲而關鍵在於:
BenchmarkStore.Snapshot.warnings有零個非測試讀取者。grep -rc warnings Sources/bestasr/在整個 CLI target 零命中;每個load()呼叫端都丟棄它(
loadRecords()直接串到.projectedRecords();bench submit只用.measurements/.machines)。唯一的讀者是BenchmarkStoreTests的四個斷言,註解還寫著// still loud。所以「loud degradation」目前只存在於單元測試裡。使用者兩條路徑都看不到任何東西。
而且掉一筆 row 不會留下空缺(DA-2)
latestMeasurements是 append-only 檔案上的 latest-wins。實測:231 個 key 裡有 30 個有supersession 歷史(其中一個有 18 筆)。掉掉最新那筆的效果是靜默把已被取代的舊值升為現值
——對 #118 這種「未來新值會寫在最新 row 上」的變更,這是最壞的形狀。
Type
bug
Expected
至少其一:
publishedKeys只需要modelId|corpusId|machineId|measuredAt就能算 dedupe key,不需要解出整個MeasurementRow。用一個只含這四個欄位的
Decodablestruct 讀,未知的 provenance 值就不會讓整筆 row 消失。Snapshot.warnings至少有一個生產讀取者(CLI 印出來),讓降級真的可見。DecodeDeterminism的 doc comment 留下這個警告,但那只是文件、不是機制。Impact
Sources/BestASRKit/Contribution/Sharing.swift(publishedKeys)、Sources/BestASRKit/Store/BenchmarkStore.swift(warnings 的可見性)、Sources/bestasr/(若要印 warning)。為什麼是 follow-up 而非 #130 的 in-scope fix
DA 的 scope 判準:「這個 PR 可以修它自己寫的文字、它自己弄假的文字、以及它自己建立的檔案裡的
測試——不修它只是讓人看見的東西。」
try?與 warnings-無人讀 都是先前既有的缺陷(四張表都受影響),#130 只是讓它們更容易被觸及。但 DA 也指出這個框架只對一半:
publishedKeys註解所記載的前提(「CI-valid ⟹ locally decodable」)是被 #130 弄成假的——所以 #130 有責任在文件層標註,
機制層的修復則屬本 issue。
Source: surfaced during /idd-verify PR #130 — Devil's Advocate DA-1 + DA-2(五個 verify
leg 中唯一發現 warnings 無讀者的一個)。