病理報告 · 標本 05

實測數字唯一來源:docs/measurements/2026-07-26-reproducibility-4x-5.jsonsweep.measuredAt 2026-07-26T05:52:29.671Z、isFullSweep: trueproblems: []runsPerMode: 3 —— 66 筆完整六標本掃描,現行正典檔,見 phase2:1059-1062)。 其他 session 的數字只以「已作廢」或「另一輪」的身分出現,並逐一標明出處。 本文引用 phase2:行號 = docs/phase2-expected-results.mdts:行號 = specimens/05-layout-shift.ts。行號會漂,引用時連內容一起引(phase2:1199)。


05 版面位移(Layout Shift / CLS)

病症一句話:載入後靜置、零互動,三個排程在 300 / 900 / 1500ms 的位移源 (無尺寸圖片、字族換入、上方插入橫幅)落進同一個 CLS session window 並累加, CLS = 0.2694(本輪三輪逐位元相同;「差」門檻 0.25,登記於 phase2:254); 三段累加治療逐一預留空間之後,全治療臂 fixed-banner 一筆 layout-shift entry 都沒有

絕對值標 session:0.2694 出自 2026-07-26 完整掃描(4x、CDP、buildId 0.1.0-ms191c71)。 CLS 是純幾何量、三輪逐位元相同(phase2:1317),但它的「幾何確定」建立在 一組被護欄計數器盯著的前提上(字數、字族解析、圖片尺寸 —— 見誠實揭露), 不標條件就引用仍然是錯的。

凍結條件

同一組條件之間才能比較。任何一項改動,先前所有數字作廢。

CPU throttle 4x —— 宣告值,JS 偵測不到(sweep.cpuThrottlerecords[*].cpuThrottle)。CLS 登記為與 throttle 無關(phase2:259-261),但本份 JSON 沒有 1x 臂,這句宣稱本輪無法檢核
驅動方式 CDP 機器驅動(sweep.driver)—— 但本標本 action: 'idle',驅動器只負責導覽與靜置,不派送任何輸入(互動會經 hadRecentInput 豁免毀掉主指標,ts:40-43
viewport 800 × 600(src/specimens.ts:10 FROZEN_VIEWPORT)。量測寬度另外凍結成 769pxhtml { overflow-y: scroll; } 讓捲軸從第一幀就佔位(ts:286),護欄 records[*].custom.contentWidthPx 12 筆全為 769。CLS 的分母是扣掉捲軸後的 785 × 600 視窗(ts:477-480 逐位驗證),不是 800 × 600
refreshHz 60(records[*].refreshHz)—— 本標本主指標與幀率無關,droppedFramesPeak 12 筆皆 0
操作程序 idle · 載入後靜置 · repetitions: 1intervalMs: nullsrc/specimens.ts:344-350
buildId 0.1.0-ms191c71records[*].buildId
protocolVersion 1(src/protocol.ts:8 PROTOCOL_VERSION;records 未載此欄位)
dispatchSpanMs 不適用 —— idle 協定沒有絕對排程節拍,records 無此欄(無派送可言,不是 0)

B 類量測法(本輪數字的成立前提):切 mode 必須重載整份 document(LCP per-document、 CLS 是 document 級累計值,ts:431-435)。本輪採用 B 類前導污染修正後的方法: 每一筆樣本從全新的 deep-link 導覽開始、CPU 節流在導覽之前打開、 另加一次丟棄的暖身導覽吃掉冷啟動(phase2:989-1001)。 同一節已驗證 #5 的 CLS 完全未受前導污染(四臂三輪逐位元相同、與修前同值 —— CLS 不掛 document 時鐘,phase2:1046-1047);LCP 欄則是載入期指標, 本輪的 LCP 是在修正後的隔離法之下量得的。

動工前登記的預期

登記出處:原始登記 phase2:235-285;重新設計登記(位移源二補上真實位移、 單一 fixed 臂拆成梯度三段)phase2:646-737;判準定案追記 phase2:1302-1317這一節不准回頭改去迎合實測。 修正只在該檔「修正紀錄」追加。

實測

三輪,同一組凍結條件。可重現性判定用每輪 median 不用 max(protocol.ts:309 「抗離群。可重現性判定用這個,不用 max」);CLS 每輪只有一個終值 (records[*].cls.value),該值即每輪的代表值,無輪內分布可言。 相對離散度 = (max − min) / median-of-three;絕對底線 CLS 0.01 (tools/analyze-repro.mjs:54)。

mode 三輪 CLS 相對離散度 絕對全距 sessionCount 判定
broken 三個位移源 0.269378 / 0.269378 / 0.269378(逐位元相同) 0.0% 0 1 / 1 / 1 ✅ 可重現
fixed-image 0.102056 ×3(逐位元相同) 0.0% 0 1 ×3 ✅ 可重現
fixed-font 0.088652 ×3(逐位元相同) 0.0% 0 1 ×3 ✅ 可重現
fixed-banner 無 entry ×3 —(無值可算) 0(三輪一致無 entry) 無 entry ✅ 可重現

出處:records[mode=broken,run=1..3].cls.value = 0.26937771106332914 ×3、 records[mode=fixed-image,run=1..3].cls.value = 0.10205648910706316 ×3、 records[mode=fixed-font,run=1..3].cls.value = 0.08865229421071848 ×3、 records[mode=fixed-banner,run=1..3].cls = null ×3。

⚠️ fixed-bannernull 是「無 entry」,不是「量到 0」。 ClsCollector.current() 在一筆 entry 都沒收到(含被豁免的)時回 nullsrc/measure/vitals.ts:200-203「面板才能區分『沒有位移』與『還沒開始觀測』」; 快照經 runtime.ts:269 取值。phase2:1306 引的 runtime.ts:193 已漂移, 現指向 crossCheck 的欄位,機制敘述不變)。對 CLS 而言 observer 掛著、沒東西可報, 語意上就是位移為零 —— 但記法必須是「無 entry」,這是標本 #3 治療版建立起來的區別 (模板前言),不因為結果是好事就省略。依生效範圍條款這裡不宣稱「通過 < 0.02」。

量化假象(登記在案,本輪單邊落點)broken 的位移源一可能記成一筆或兩筆 entry (alt 盒塌陷 + 20ms 後撐開,兩步是否同幀不定),兩個離散落點 0.24741 / 0.26931、 之間沒有中間值(ts:118-129)。本輪三輪全部落在拆兩筆值 0.269378; 同日稍早的 #2/#5 驗證輪(2026-07-26-reproducibility-4x-4.json,另一份 JSON, 僅作機制佐證、不作絕對值比較)三輪是 0.2474 / 0.2474 / 0.2694(phase2:1009)—— 兩個落點各自逐位可重現。sessionCount 不受此影響(ts:129)。

護欄計數器(records[*].custom,每臂三輪皆相同)

護欄 登記值 broken fixed-image fixed-font fixed-banner
contentWidthPx 769 769 769 769 769
proseCharsCollapsed 202 202 202 202 202
captionCharsCollapsed 444 444 444 444 444
proseHeightBeforePx → AfterPx 112→140 / 168→168 112→140 112→140 168→168 168→168
figureHeightAtFontShiftPx / figureNaturalHeightPx 360 / 360 360 / 360 360 / 360 360 / 360 360 / 360
bannerPushPx 72(前三臂)/ 0 72 72 72 0
clsIgnoredByInput 0(風險 R2 未觸發) 0 0 0 0
shiftSourcesScheduled 3(排程數,不是 entry 數,ts:118-142 3 3 3 3
captionTopPx(掛載時) —(觀測值) 343.875 679.875 735.875 807.875
captionVisibleBeforePx —(觀測值) 208 0 0 0

4 臂 × 3 輪共 12 筆,護欄全部命中登記值captionTopPx 逐臂下移的差額 (+336 / +56 / +72)正是各段預留的空間(圖片 360 − alt 盒 24、內文 168 − 112、 橫幅 64 + 邊界合併的 8,ts:59-68)——預留逐段生效的幾何直接寫在護欄裡。 captionVisibleBeforePx 208 → 0 顯示:治療臂把圖說整段推到摺線下, 這是撤銷 R3 後「裁切量自身可觀測」的設計在動作(phase2:716-721)。

次指標 LCP(B 類附帶)

mode LCP 標的(三輪一致) 三輪 LCP (ms) median 相對離散度 絕對全距
broken p#ls-caption 92 / 108 / 72 92 39.1% ⚠️ 36ms(< 50ms 底線 → ✅)
fixed-image div#ls-prose 84 / 84 / 76 84 9.5% 8ms
fixed-font img#ls-figure 384 / 376 / 388 384 3.1% 12ms
fixed-banner img#ls-figure 380 / 404 / 384 384 6.3% 24ms

出處:records[mode=*,run=1..3].lcp.value.lcp.el

⚠️ 四臂三種 LCP 標的,這一欄不得跨臂引用phase2:1231-1232)。 治療臂 LCP 較大是標的換人broken 的 LCP 是第一次繪製就定案的圖說文字, fixed-font/fixed-banner 的 LCP 是要等網路的圖片 —— 不是「治療讓頁面變慢」 (ts:538-543)。機制上圖片在 broken 臂反而因可見面積較大而被 低熵規則(< 0.05 bpp)排除在 candidate 之外(校準 D 規則 phase2:32ts:524-536 以 998 / 1198 bytes 兩點證偽驗證過門檻位置)。 先前「aspect-ratio 預留後圖片才有資格當標的」那句無證據的因果解釋已刪(phase2:723-728)。 ⚠️ ts:513-543 檔尾的 LCP 推導寫於單一 fixed 臂時代,其「fixed-*img#ls-figure」對 fixed-image 臂不成立(本輪實測是 div#ls-prose); 逐臂標的以 phase2:862 與本表為準。 broken 臂相對離散度 39.1% 超過 30% 門檻,靠絕對全距 36ms < 50ms 底線判可重現。

互動期欄位totalInteractions 12 筆皆 0(idle 協定設計如此); inp / inputDelay / processing / presentation / durationnull = 未量測 (無互動可量,不是量到 0)。捲動與點擊都會污染主指標,零互動是實驗條件不是缺漏。

兇手歸因

broken fixed-banner(全治療臂)
inputDelay 未量測(idle 協定、totalInteractions 0) 未量測(同左)
processing 未量測 未量測
presentation 未量測 未量測
LoAF forcedStyleAndLayout(僅標本自己的 script) 無 entry(forcedSamples: []loafPickedBy: "none",三輪皆同) 無 entry(同左)
sourceFunctionName 無 entry 可指認(forcedFn: null 無 entry 可指認

三輪兇手段是否一致: —— 兇手是登記的 cls 本身(src/specimens.ts:342), 證據不在 INP 三段(本標本沒有互動),在 CLS 的梯度逐段拆解(見治療梯度): 每臂三輪 CLS 逐位元相同、sessionCount 一致,位移源逐段移除時分數逐段消失。

⚠️ tools/analyze-repro.mjs 的「三輪一致兇手 vs 登記值」判準只涵蓋 INP 三段, culprit: 'cls' 落在值域之外(not-an-inp-segmentphase2:1166-1180)—— 登記的兇手從未被自動判準驗證過。本報告的歸因靠梯度差分與護欄計數器,不靠該判準。 LoAF 一欄同時是排除證據:三個位移源的實作路徑上沒有留下任何強制版面幀 (位移源一刻意一行 DOM 量測都不做,ts:162-165;源二、源三的 offsetHeight / getBoundingClientRect 讀取沒有觸發可觀測的 LoAF entry)。

治療梯度

治療 唯一翻動的變因 三輪 CLS 相對病變(同一 JSON 內,描述值) 代價
fixed-image .ls-figureaspect-ratiots:291 0.102056 ×3 2.64×(0.269378 ÷ 0.102056) 必須事先知道圖片內在比例;比例錯了空間照樣跳
fixed-font 再加 .ls-prosemin-height: 168pxts:306 0.088652 ×3 3.04×(0.269378 ÷ 0.088652) 刻意多留一行 = 常態多 28px 空白(ts:298-303);是替代解不是正解(正解 size-adjust 需自架字型);min-height 與文案長度耦合,改字要重量(ts:349-354
fixed-banner 再加 .ls-banner-slotmin-height: 64pxts:314 無 entry ×3 不報比值 —— 分母無 entry,除法無定義(phase2:1310-1312 頁面從第一幀起常駐 64px 的空 slot;等價替代(position: fixed 疊加)會遮內容(ts:230-234,未做臂)

逐段歸因(同一份 JSON 內的差分,每臂只差一個位移源)

與標本檔尾逐筆推導的獨立計算相符(源一拆兩筆 0.16726、源二 0.013409、 源三 0.088652,ts:487-511;源一差 0.00006 來自登記註解的成分捨入)。 梯度拆臂讓歸因不需要擴充協定送逐筆 entry —— 臂間的 cls.value 差異本身就是歸因 (phase2:678-679phase2:857-860)。

方向:0.269378 > 0.102056 > 0.088652 > 無 entry —— 嚴格單調遞減, 與梯度設計的結構性預測同向(phase2:1313-1317)。依生效範圍條款 (phase2:1334-1338),本報告不宣稱通過或未通過任何比值/單調判準, 上述只是方向與絕對值。

位移源二那段只值 0.01340 —— 這不是「治療二效果小」,是分數被摺線壓小: 它推動的插圖有 65px 已在摺線以下、不進帳(ts:489-493), 貢獻由裁切量決定(phase2:859)—— 這正是撤銷「三源都須在第一屏內」條款時 登記的機制(phase2:716-721)。無效或反向的治療:

與登記的差異

誠實揭露