mirror of
https://github.com/block/buzz.git
synced 2026-11-12 20:31:12 +00:00
fix(desktop): rekey upscroll momentum gate onto rendered scroll (w4a-gate-1)
The mid-history correction's momentum-skip gate keyed on the raw `scrollTop` delta since baseline. On WebKit, momentum is coalesced into `scrollTop` on the compositor's own async clock, so a frame that PAINTED still can read a large raw delta and wrongly skip a genuine above-anchor reflow — the reversal survivor bin (the 204px-class lurch of #1662). Rekey the gate onto the RENDERED scroll — the painted wheel motion this frame — `renderedScroll = aboveShift - ΔtopOffset`: the anchor's painted on-screen move with the reflow's own push removed, both terms read from the painted DOM (getBoundingClientRect), not the possibly-ahead `scrollTop`. A rendered-still frame now reads ~0 and the reflow is corrected instead of dropped. Because the gate now needs `aboveShift` to decide, the band walk runs before the gate. To keep "under-correcting is invisible; the next quiet frame catches up," `sumAboveAnchorShift` no longer refreshes the height cache inline — it STAGES the refresh and returns `{ aboveShift, commit }`. The caller applies `commit()` only past the gate, so a momentum skip leaves the cache for the next frame; a kept correction refreshes it as one indivisible pass (the "second observer no-ops" invariant is intact). Arbiter contract, fresh w4a-gate-1 build, both engines: - raf-correction HARD gate: Chromium 0 reversals, rAF fires 0 / RO 21 (RO sole writer); WebKit 2 reversals max 14.5px (<=34 quantum floor), rAF fires 24 / RO no-op (residual 0.0). Ratified invariants hold. - slow-scroll: 0 reversals both engines (felt low-velocity regime clean). - fast-classify DECOMPOSITION self-test (WebKit): pure-reflow attempts median |signedShift|=18.5 but median |renderedScroll|=0.0 — the reflow does NOT leak into the gated quantity, and 19/28 fire. Pure-scroll |renderedScroll| runs up to 28. The decomposition is proven, not asserted. Guarded WebKit-only: on Chromium the rAF is the passive loser observer (RO corrects first), so renderedScroll there tracks signedShift by construction — characterized, not asserted. KNOWN RESIDUAL (surfaced, not hidden): 2 WebKit survivors remain, but they are a DIFFERENT class — signedShift=0.0 (the band walk sees no above-anchor reflow) while the row still lurches 14.5px. The momentum-gate survivors the rekey targeted are gone; these are cross-check/null-target skips where the reflow is invisible to the band walk. Separate diagnosis. Diagnostic-only `renderedScroll` is threaded through the shared result type + emitted on the rAF probe so the fixture can prove the decomposition; stripped/gated before merge per the file-size exit condition. Raises the useAnchoredScroll.ts size exception 1180->1210 to cover the arm (biome reflows the 4-prop returns); flagged in the override comment for Eva as heavy-for-a-diagnostic. Co-authored-by: Tyler Longwell <tlongwell@block.xyz> Signed-off-by: Tyler Longwell <tlongwell@block.xyz>
This commit is contained in:
parent
44d9edcf2f
commit
2bd2076ebb
@@ -189,16 +189,23 @@ const overrides = new Map([
|
||||
// (Quinn's merge-bar checklist #4), the one-clock/single-writer reasoning, and
|
||||
// the build-stamp/probe contract are all documented AT their sites. The file
|
||||
// was 888 lines at HEAD; this fix's code + load-bearing provenance comments
|
||||
// crossed 1000. The 1140→1180 bump is the W4a chase instrumentation inflating
|
||||
// crossed 1000. The 1140→1210 bump is the W4a chase instrumentation inflating
|
||||
// a load-bearing hook mid-investigation: the signed-shift grow/shrink probe
|
||||
// (classifier arm) and the renderedScroll gate-clock rekey (w4a-gate-1 arm),
|
||||
// both carrying their provenance inline. EXIT CONDITION: once #1662's fate is
|
||||
// decided, the diagnostic emits get stripped or gated and the mid-history
|
||||
// corrector + band walk split into a sibling module — Eva's ruling holds the
|
||||
// structural split until the arms in flight against this file settle, so it is
|
||||
// NOT done mid-chase. Comment-dominated overage on a correctness fix, not
|
||||
// generic debt growth. Approved override; queued to split with the rest.
|
||||
["src/features/messages/ui/useAnchoredScroll.ts", 1180],
|
||||
// (classifier arm, 1140→1156) and the renderedScroll gate-clock rekey
|
||||
// (w4a-gate-1 arm, ~1156→1206). The gate-arm growth is the deferred-refresh
|
||||
// commit path + the momentum-gate rationale + the `renderedScroll` field
|
||||
// threaded through the shared result type and all four returns so the
|
||||
// classifier fixture can PROVE the scroll/reflow decomposition (Eva required
|
||||
// this in the arm's first run); biome reflows each 4-prop return object to
|
||||
// multi-line, which is most of the line cost. FLAGGED to Eva: this is heavy
|
||||
// for a diagnostic — if the decomposition proof moves behind a lighter
|
||||
// gate-only probe, this drops back toward 1185. EXIT CONDITION: once #1662's
|
||||
// fate is decided, the diagnostic emits get stripped or gated and the
|
||||
// mid-history corrector + band walk split into a sibling module — Eva's ruling
|
||||
// holds the structural split until the arms in flight settle, so it is NOT
|
||||
// done mid-chase. Comment-dominated overage on a correctness fix, not generic
|
||||
// debt growth. Approved override; queued to split.
|
||||
["src/features/messages/ui/useAnchoredScroll.ts", 1210],
|
||||
// AgentConfigPanel footer fold into ProfileFieldGroup for the config-bridge
|
||||
// panel — a small overage from load-bearing UI plumbing, not generic debt
|
||||
// growth. Approved override; still queued to split with the rest of this list.
|
||||
|
||||
Reference in New Issue
Block a user