Skip to content

test(studio): fail edit accuracy cases whose preview flashes or paints an edit late - #4796

Draft
miguel-heygen wants to merge 12 commits into
mainfrom
test/studio-edit-accuracy-flash
Draft

miguel-heygen wants to merge 12 commits into
mainfrom
test/studio-edit-accuracy-flash

Conversation

@miguel-heygen

@miguel-heygen miguel-heygen commented Sep 30, 2026 •

Copy link
Copy Markdown
Collaborator

What

The edit accuracy bench gains two metrics that feed the case pass:

  • flash: from each committing input (pointer-up, key, undo, redo) and from a reload, to the settle, every painted frame must match the state before the input or the settled state after it, in the preview pane (with its chrome), the timeline pane and the inspector pane. A frame that matches neither is a flash.
  • paint (edit-to-paint): the first frame painted after a committing input must already show the after-state, and arrive no later than a dropped frame (25 ms). Reported in frames and ms.

How

  • Page.startScreencast (JPEG q95, every frame, each frame acked at once) runs only in the untraced windows after the drag; the drag keeps its trace.
  • A 16x16 marker in the top document, outside every pane, repaints each rAF with a frame counter in its colour (5 bits per channel in steps of 8, which survives JPEG), so every frame is sent and numbered. The marker also logs the counter at each committing input, in the top document and every same-origin frame (including the player's shadow root).
  • Coverage is counters seen over counters in the window. A window is uncovered (never a pass) under 90%, or under the same run's blank-page control minus 5 points. The table lists each case's 1-frame miss chance (1 - coverage).
  • Chrome runs with --disable-gpu-compositing: under swiftshader GL the screencast saw 40-70% of Studio's frames during heavy windows (Chrome drew 87 frames, the screencast delivered 35); with software compositing it sees about 95%.
  • Tolerance per pane: the pixel count a 0.5 px shift of the element's perimeter touches.
  • Nudge: the first four steps stay traced for smoothness; the fifth runs in the capture window as the committing key (the blank-page control traces four as well).
  • Gate: a metric the base branch's baseline never measured is judged only for banking, so adding a metric cannot regress the gate.

Controls

Main at ca3a3f6, this bench, one case (rotate-none-px-r0-root-z100) unless named, one job per run.

Control Runs Result
2-frame preview blink after pointer-up 20 caught 20/20 (release coverage mean 0.92)
1-frame preview blink after pointer-up 20 caught 20/20 (release coverage mean 0.91)
Same blinks without software compositing 20 + 20 caught 16/20 and 15/20 (coverage mean 0.41 and 0.40)
Forced preview iframe reload 100 ms after pointer-up 10 caught 10/10: 6-23 preview frames per run
No-move tap 10 0 flash frames in every window, paint 1 frame
Clean repeat (no control) 10 0/10 with a frame in the blink slot; 0-4 release frames of a real defect (below)
Real defect, move-none-px-r0-nested-z100, with marker 5 caught 5/5: undo 4-7 frames, redo 4-11
Same, without marker 5 caught 5/5: undo 6-10 frames, redo 7-10

"Caught" for a blink means a preview-pane bad frame within 4 frames of the pointer-up (the blink is injected by a page call after the release). No gesture on main is free of flashes today: every case screened shows the timeline emptying for several frames on undo and redo, and rotate shows 1-2 frames of mixed selection chrome after release. So a whole-case "0 flashes over 10 runs" control is not available yet; the no-move tap stands in for it. With and without the marker the counts are separate runs of a defect whose length varies, and without the marker repeated frames cannot be deduped, so they do not agree within one frame.

Slice (gsap=none, main ca3a3f6)

(filled in with the run)

Before

Without the flash metric the bench saw only the settled undo, which matches the state before the move.

Settled undo: one clip on the timeline

After

The flash metric flags the frames in between: mid-undo, the timeline shows no clips at all.

Mid-undo frame flagged as a flash: empty timeline

Work in progress: the ratchet and its tests; the CI job follows.
Shares the built CLI from the Build job, re-runs twice each case that passes on the base branch and failed, and posts one sticky comment from the gate job.
… banking them

The shards re-ran only regressions, so one lucky pass of a base-failing case failed the gate as unbanked and was never listed as unstable. Every case whose verdict differs from the base branch, either way, is now re-run twice and judged 2 of 3. A render error fails the gate like an unsettled snapshot, a malformed baseline.json fails the job instead of reading as empty, and the header is 3 lines.
…s an edit late

Edit-to-paint: the first frame after a pointer-up, key, undo or redo shows the after-state.

A metric the base baseline never measured cannot regress the gate; it counts for banking.
…t a blank control

PNG capture misses 11-23% of frames even on a blank page, so every case read uncovered.
… than a dropped frame

A pointer-up whose next frame arrived 507 ms later passed on frame count alone.
Base automatically changed from test/studio-edit-accuracy-ci-gate to main September 30, 2026 23:32
…so flash capture keeps up

Under swiftshader GL the screencast saw 40-70% of Studio's frames; software compositing sees ~95%.
…sh controls and input log

The previous commit only switched the frame check to the live URL; the iframe walk did not land.
@github-actions

github-actions Bot commented Oct 1, 2026

Copy link
Copy Markdown

Edit accuracy: 264 passing here, 434 on the base branch

The gate fails: 170 case(s) that pass on the base branch fail here; the passing count fell from 434 to 264; baseline.json marks 434 failing case(s) as passing.
Smoothness is reported in the artifact, not gated. A case fails only if it fails 2 of 3 runs.

Regressed (170)

  • move-hold-center-r0-nested-z100
  • move-hold-pct-r0-root-z50
  • move-hold-pct-r30-root-z200
  • move-hold-px-r0-nested-z100
  • move-hold-xpercent-r0-root-z50
  • move-none-center-r0-root-z50
  • move-none-center-r30-root-z200
  • move-tween-center-r0-nested-z100
  • move-tween-pct-r0-root-z50
  • move-tween-px-r0-nested-z100
  • nudge-hold-center-r30-root-z200
  • nudge-hold-pct-r0-nested-z100
  • nudge-hold-px-r0-root-z50
  • nudge-hold-xpercent-r0-nested-z100
  • nudge-tween-pct-r0-nested-z100
  • nudge-tween-px-r0-root-z50
  • nudge-tween-px-r30-root-z200
  • resize-hold-pct-r0-nested-z50
  • resize-hold-pct-r30-nested-z200
  • resize-tween-pct-r0-nested-z50
  • resize-tween-pct-r30-nested-z200
  • resize-tween-px-r30-root-z100
  • move-hold-center-r0-root-z100
  • move-hold-center-r30-nested-z50
  • move-hold-pct-r0-nested-z200
  • move-hold-px-r0-root-z100
  • move-hold-px-r30-nested-z50
  • move-hold-xpercent-r0-nested-z200
  • move-tween-center-r0-root-z100
  • move-tween-center-r30-nested-z50
  • ...

Marked passing in baseline.json but failing (434)

  • crop-hold-center-r0-nested-z200
  • crop-hold-pct-r30-nested-z50
  • crop-hold-px-r0-nested-z200
  • crop-hold-xpercent-r30-nested-z50
  • crop-none-center-r0-root-z100
  • crop-none-center-r30-nested-z50
  • crop-none-pct-r0-nested-z200
  • crop-none-px-r0-root-z100
  • crop-none-px-r30-nested-z50
  • crop-tween-center-r0-nested-z200
  • crop-tween-pct-r30-nested-z50
  • crop-tween-px-r0-nested-z200
  • crop-tween-xpercent-r0-root-z100
  • crop-tween-xpercent-r30-nested-z50
  • move-hold-center-r0-nested-z100
  • move-hold-pct-r0-root-z50
  • move-hold-pct-r30-root-z200
  • move-hold-px-r0-nested-z100
  • move-hold-xpercent-r0-root-z50
  • move-hold-xpercent-r30-root-z200
  • move-none-center-r0-root-z50
  • move-none-center-r30-root-z200
  • move-tween-center-r0-nested-z100
  • move-tween-pct-r0-root-z50
  • move-tween-pct-r30-root-z200
  • move-tween-px-r0-nested-z100
  • nudge-hold-center-r0-root-z50
  • nudge-hold-center-r30-root-z200
  • nudge-hold-pct-r0-nested-z100
  • nudge-hold-px-r0-root-z50
  • ...

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant