Repository navigation
feat(core,engine): report why blur is off, and what each render session did - #5991
vanceingalls wants to merge 1 commit into
Conversation
7408da4 to
bf775cc
Compare
d306aaa to
201da6a
Compare
bf775cc to
4f40902
Compare
201da6a to
b036dee
Compare
miguel-heygen
left a comment
There was a problem hiding this comment.
Reviewed exact head b036deef790b8897bd6c805b94ff861182baec2a relative to 4f40902c27d2c38ee4ee35f73e80983af29dd480.
Audited stable reason codes, probe/restore, sticky suspend/re-init, first-frame and session-end reporting/timeout and close consumer. Own delta has no additional demonstrated blocker. The four pixel tests have explicit browser/API skip conditions; I read their assertions, did not execute a real Chrome pixel run, and do not treat the child's3 generic regression cases as that proof. Inherited #5971 detector gap still holds the composition.
Independent revision-bound review of the nine-PR composition. Earlier approvals/requests covered older heads. Current saved head/review/inline/check snapshot has no fresh duplicate finding and no failing/pending latest check. Stacked broad-suite skips are not executed tests.
Audited: Stable reason codes, probe time restoration, sticky suspend/re-init, first/end diagnostics and closing timeout; read pixel-test assertions and skip conditions.
Limits: Composed local focused run:196 authored core tests pass; separate WAAPI/CLI44 pass. Synthetic geometry/canvas controls, not fresh browser pixel/performance proof. No app/model/provider call, source fix, merge or release.
— Magi / desktop-review
Verdict: APPROVE
Reasoning: No additional blocker in this own delta. The later #5971 defect must be repaired before landing the complete stack.
…on did Tooling and logs need more than "off". Give the runtime's report a reason code for every way blur can be off (renderer-off, unsupported-browser, each html-in-canvas defect, capture-failures), and two calls for tooling: probe() runs the same scan a render would, without painting, and suspend() stops all painting for the rest of a session without changing the reported decision. The engine prints one line per session from what the page reports: `[motion-blur] on reasonCode=null movers=N failedFrames=K`. The first-frame line cannot know about later failures, so the session end prints the same line with "(session end)" when any frame fell back to plain DOM; a clean session stays quiet. A render where every capture failed no longer reads as "on" with nothing else. Add the first test that reads blurred pixels: real Chrome with html-in-canvas, the engine's frame order (seek, wait, composite, screenshot). It checks the trail along the motion line, that what does not move matches the sharp frame, that a box centered with translate is blurred where it really is, and that a flipped backface card renders the plain frame. It skips when Chrome or html-in-canvas is missing. Folded review fixes: R13 (runtime half), R17 (engine half), T1 (the guards that need reason codes), T3 (log-line and pixel tests). Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
4f40902 to
83f05ec
Compare
b036dee to
7693556
Compare
miguel-heygen
left a comment
There was a problem hiding this comment.
Reviewed exact head 7693556e8860654d3b40dd99d238445b58996aee against its actual parent 83f05ec5fd2d0bcb3f8188e7bc1f9cbc5f63ece9 and the previously reviewed tree.
The restack retains the repaired detector/cache; added browser assertions cover CSS/WAAPI faces, between-sample frame fallback and flat-face allowance. The moved chunkFrames test blob matches the previously reviewed test exactly. These browser tests explicitly skip without Chrome/runtime/drawElementImage; I read them but did not run a fresh pixel experiment.
Independent verification: own-head and composed-tip synthetic computed-style controls 4/4 pass; predecessor witness remains red (inline positive passes). Exact-source authored detector suites run locally:31 own-head +47 tip tests pass, including WAAPI containment, named/multiple animations and cached-candidate retention. The computed animation-name seam is explicit because jsdom does not expand animation shorthand. These are deterministic detector controls, not fresh Chrome pixel/performance proof.
Current exact-head check snapshot has no failed or pending check. Read completed regression gate logs and executed #5991 preflight lint/format output; stacked broad-suite skips and aggregate gate success do not prove execution of the new pixel/unit suites. Author Chrome152 experiments, 26ms scan cost and package-budget margin remain attributed.
Known sampling limit remains: a short WAAPI-only face absent at every scan cannot enter the cached set. This bounded sampling residual differs from the repaired omission of ordinary animation-derived candidates; no universal detection guarantee is claimed. No new source blocker found in this successor composition. No browser/app/model call, merge or release.
— Magi / desktop-review
Verdict: APPROVE
Reasoning: The earlier animated-face candidate blocker is repaired and retained through the restacked composition; no additional blocking change was found.

What
Reports why blur is off, and what each render session did, so tooling and logs can tell.
report()carries a stablereasonCodenext to the readablereasonfor every way blur ends up off: a defect code (from feat(core): block capture motion blur on html-in-canvas defects #5971),unsupported-browser,renderer-offandcapture-failures.probe()(onwindow.__hfMotionBlur) makes the decision on demand without wrapping or painting; it is cheap once scanned and puts the playhead back.suspend()stops all painting for the rest of a session without changing the reported decision (and never sets the page's off switch, which would change the probe's answer). It outlives a re-init of the same root and does nothing where blur is off.[motion-blur] on reasonCode=null movers=N failedFrames=K, after the first frame. The first-frame line cannot know about later failures, so the session end prints the same line with(session end)when any frame fell back to plain DOM (read with a 1.5 s timeout so a stuck page cannot hold up closing); a clean session stays quiet.captureMotionBlur.pixels.browser.test.tsdrives a real Chrome with html-in-canvas through the engine's frame order (seek, wait, composite, screenshot) and checks: the trail along the motion line has the hard edges of the sharp frame spread out without adding or losing ink; what does not move matches the sharp frame exactly; a box centered withtranslate: -50% -50%is blurred around where it really is; a backface-hidden card in a 3D flip renders the plain frame.distributed/chunkFrames.test.ts(moved here from feat(core,producer): decide blur defects once per timeline, off on routes that cannot host it #5990 to keep that PR under 1000 lines): a chunk session stands page blur down and asks for no engine blur. Also a face whosebackface-visibility: hiddencomes only from@keyframesorelement.animate(), next to an ordinary mover, turns blur off withbackface-visibilityand renders the plain frame; a face that is hidden only between two scan samples renders just that frame plain; a flat animated backface hack stays blurred. It skips when Chrome or html-in-canvas is missing.Why
Part 8 of 9 in the capture motion blur stack: #5875 → #5967 → #5968 → #5969 → #5970 → #5971 → #5990 → #5991 → #5992. It builds on #5990, whose scan decides the state this reports.
Stack goal: opt-in capture motion blur for compositions, in Studio preview and in renders, drawn with Chrome's html-in-canvas. Blur turns itself off in several cases, and without this an author or an operator cannot tell which;
hyperframes check(#5992) builds onprobe()andsuspend().Notes
statestaysonwhile individual frames fall back to plain DOM (a paint timeout, a missed defect, a failed capture): readfailedFramesfor those. A paint timeout counts infailedFramesbut not infailures, which only counts capture exceptions in a row (documented, not fixed).window.__hfMotionBlur.report()(state,reason,reasonCode,movers,failedFrames), the per-session log line, and, in feat(cli): tell authors in check why motion blur is off #5992,hyperframes check.CanvasDrawElementfeature; it is a guard for the pipeline, not a visual-quality benchmark. Limits it does not cover: trails drawn over foreground elements, a halo on transparent movers, trails pastoverflow:hidden, 2D flips throughscaleX = 0.Testing
captureMotionBlur/index.test.ts: reason codes for every off path (the earlier assertions on reason text now check codes too),probe()finds the movers without any paint, wrap or event and restores the playhead, does not rescan unless the timeline changes or while blur is off, reports the defect with its code andcapture-failuresafter three failed frames;suspend()unwraps a wrapped root, stops painting, is idempotent, outlives a re-init, exists but does nothing where blur is off, and lets the probe still decide; plus the guards that need codes (one warning and the first reason stays when unwrapping throws).pageMotionBlur.test.ts: the per-session line, the session-end line only when frames fell back (including when the failures ended blur), the timeout for a page that does not answer, andcloseCaptureSessionlogging the closing line once before the page closes (driven through the real function);frameCapture-motionBlur.test.ts: the line is logged once after the session's first captured frame, says why blur is off, and stays silent for a page that never asked for blur.captureMotionBlur.pixels.browser.test.ts: 4 pixel tests in Chrome 152 headless shell.bun run build,tsc --noEmitin core and engine, and their tests pass; comment ratchet against feat(core,producer): decide blur defects once per timeline, off on routes that cannot host it #5990's branch passes; every package is within its size budget.🤖 Generated with Claude Code