Repository navigation
perf(studio): settle the edit accuracy bench on frames and network, and reuse the producer Chrome - #5571
Conversation
3fee7ba to
6e02386
Compare
2802382 to
fe9f10c
Compare
Edit accuracy: accurate 271 (base branch 271), smooth 171 of thoseThe gate passes. Quarantined, measured but not gated (0) Unstable (1)
|
…ot a fixed window settled() waited for the box and the preview frames to hold still for 500 ms, 7 to 15 times a case. It now resolves once they read the same on 3 animation frames in a row while the Studio page has no request in flight (the event stream and server-rendered timeline thumbnails excepted) and the server has announced every project file written since its last file-change event, so a save, a preview reload or a reload the event starts still holds it open. EDIT_ACCURACY_STILL_MS restores the fixed window with no network signal. Also polls studio_seek every 50 ms instead of 250 ms while Studio opens. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Every render launched and closed its own producer Chrome. The run now holds a lease on the engine's pooled browser (a capture session with the renders' launch settings and its page closed), so each render opens a page in that browser instead. Each render still gets its own page and file server, and clears the browser cache first. A held browser that failed to launch or whose Chrome died is dropped and held again, never reused. Studio's server stays per case: it serves one project folder, stamps it on start and keeps that folder's undo history open, so switching folders under it would leak history between cases. Its start is polled every 50 ms instead of 200 ms. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
fe9f10c to
72819c1
Compare
jerrai-bot-heygen
left a comment
There was a problem hiding this comment.
New function-local imports in the edit-accuracy tests need to move to module scope without breaking the mock seam. Studio CI/accuracy-gate completion and the asserted baseline teleport failure remain independent verification boundaries. — Jerrai
| }); | ||
|
|
||
| it("holds the producer browser with the renders' launch settings and no page of its own", async () => { | ||
| const { holdProducerBrowser } = await import("./render.mjs"); |
There was a problem hiding this comment.
This newly added await import("./render.mjs") is inside a test callback, as is the second new import at line 107. Our top-level-import rule has no exception for tests. Please hoist the module import, also replacing the existing render() helper's local import at line 52; arrange the Vitest mock state so the module still sees the mocked producer before the assertions run.
…r test Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
jerrai-bot-heygen
left a comment
There was a problem hiding this comment.
Re-reviewed exact head 67f9a4044776e9fb5a519abbfd6e1e0470a1f3e7. The sole successor change hoists all three render.mjs imports to module scope without changing the test assertions or production settle/browser logic. Hosted Test (studio) executed 694 passing files, including render.test.mjs 4/4 and teleport.test.mjs 20/20, so the Vitest mock seam holds at this head; Lint/Format and four of five edit-accuracy shards were green at approval, with the last shard still running. This supersedes my prior local-import request; no merge or release by this reviewer. — Jerrai
…es away Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
jerrai-bot-heygen
left a comment
There was a problem hiding this comment.
Re-reviewed exact successor 34837239980826eba35ceb9a2f6fbc49698095b4, superseding my approval at 67f9a404. The only delta increments network activity when networkBusy drops a detached-frame request, matching the existing finished/failed-request path. That makes unsettledBy restart a busy initial window rather than waiting for the 15-second fail-loud limit; the new regression explicitly tests busy→detached→idle and the existing case checks the extra two drops. The prior head's hosted Studio suite (including render 4/4 and teleport 20/20) and five edit-accuracy shards passed. New-head checks were still running with no red result at approval; this approval is a code verdict, not a claim that the new run completed. No merge or release by me. — Jerrai
jerrai-bot-heygen
left a comment
There was a problem hiding this comment.
I need to supersede my approval at this same exact head 34837239980826eba35ceb9a2f6fbc49698095b4: the just-completed hosted Format job failed because the new packages/studio/tests/e2e/edit-accuracy/settle.test.mjs is not formatted (oxfmt --check ., job 115689181689). The detached-frame activity change itself is sound, but this diff-owned required formatting failure means the current revision cannot land. Please format the test, push, and route the new head for a fresh verdict. I did not merge. — Jerrai
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
jerrai-bot-heygen
left a comment
There was a problem hiding this comment.
Re-reviewed exact 5c7df21ff38c402fcf92fb1b709408f66df124fa. The sole change from the held 34837239 head reformats the one net object literal in settle.test.mjs; the detached-frame activity fix and regression are unchanged. This supersedes my formatting-only change request. Hosted checks had not yet emitted for this new push at approval; the preceding head's Format failure and earlier passing Studio/accuracy run are distinct, not evidence that this head's CI has executed. No merge or release by me. — Jerrai
miguel-heygen
left a comment
There was a problem hiding this comment.
Independent review of 5c7df21ff38c402fcf92fb1b709408f66df124fa, additive to Jerrai's import/mock audit.
render.mjs:149-184 preserves per-render server/page cleanup and cache clearing. case.mjs:330-357 retains geometry/frame/swap checks with network activity. All 83 edit-accuracy tests pass locally on the preceding 34837239; this successor only formats the new test. My probe exercises the actual settled loop: three quiet frames, restart on activity, waiting for a live request, timeout marking, and recovery when a request's frame detaches. Removing the network restart fails the probe. The detached-request activity fix closes the edge I reported in Slack.
Approval held on accuracy evidence: the completed predecessor accuracy gate failed 270 versus 271 accurate cases. resize-fromto-px-r0-nested-z100-on has reload 90.11 px and render 90.09 px in two of three runs, with the third passing. The current head's CI is pending; five successful shard jobs at the predecessor did not imply a passing gate.
I downloaded the actual shard-5 artifacts. All three attempts saved byte-identical index/sub-composition files (SHA256 verified), and the producer's pixel box stayed identical. The differing value is the reloaded Studio quad: its left edge is 759.98 in the two failures versus 669.92 in the passing attempt; committed/redone quads are 669.92 in all three. That narrows the investigation to reload/measurement state rather than differing saved edits or producer pixels. It does not establish whether this is a pre-existing Studio race or the shorter settle. Please resolve/explain that failed gate before approval; a paired fixed-window-fallback run would help isolate the timing change.
The author's local teleport failure is not reproduced: locally 20/20 pass, and hosted Studio executed 20/20 on 67f9a404; the file is unchanged from base.
Limits: no independent full browser benchmark, crash/cancellation fault injection, or twice-run full grid. Actual hosted PR-slice execution supplies browser evidence. Exported fixture/dependency links and read-only monitor cleaned/stopped; no installs, worktrees, merge, or workflow dispatch.
Verdict: COMMENT
Reasoning: Scoped unit/probe evidence supports the implementation and its successor fix, but the completed predecessor accuracy gate exposes an unresolved two-of-three reload/render failure and fresh CI has not established recovery.
— Magi (desktop-review)
jerrai-bot-heygen
left a comment
There was a problem hiding this comment.
I am superseding my approval at 5c7df21ff38c402fcf92fb1b709408f66df124fa after reading the completed edit-accuracy gate, not just its five successful shard jobs. The preceding functional head 67f9a404 ran the gate and failed 270/271 versus base 271/271: resize-fromto-px-r0-nested-z100-on failed reload/render by ~90 px in 2 of 3 attempts. The later 34837239 change fixes detached-request activity, and this final push only formats its test; neither is established to cure that measured position regression. At review time the new head's accuracy jobs had not emitted. Please diagnose or recover this case (or establish with a discriminating rerun that it is unrelated to this diff) before a new approval. My earlier approval incorrectly treated five green shards as a green aggregate gate. No merge by me. — Jerrai
openStudio now polls every 50 ms, so after a reload its first studio_seek often lands before the runtime binds the timeline (Studio still reports duration 0, but the playhead moves). The bind then replays the playhead from near 0 (core init.ts progress(0.0001) then totalTime). A tween that starts on the playhead was already initialised by the early seek, so GSAP skips its first keyframe. The preview then holds a box no fresh seek or render shows. In resize-fromto-px-r0-nested-z100-on that box is 90 px off, and it persists until the next seek. Wait for studio_look to report a duration before seeking. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
miguel-heygen
left a comment
There was a problem hiding this comment.
Re-reviewed exact head 707f63aeb28ea6ca05bd7f123217bb2f05ddad01; this clears my prior accuracy-evidence hold.
case.mjs:368-389 now waits for a positive duration from studio_look before the first studio_seek. Both tools read the same player-store duration, and the initial/reload path goes through this guard. The rest of the quiet-settle/browser-hold logic is unchanged.
Independent verification: all 84 edit-accuracy tests pass locally; deleting the duration guard fails the new regression. With the failed artifact's saved animation values, real GSAP reproduces early-seek x=40 versus bind-first x=-50.073. A controlled Chrome DOM/GSAP probe calling the actual seekBound likewise waits through duration 0 before seeking at duration 4 and lands at -50.073. This verifies the timing cause with a synthetic WebMCP host, not a complete Studio reload/stress test.
Current-head evidence now resolves the hold: all five executed accuracy shards and the aggregate gate pass, 271 accurate versus base 271. I downloaded shard 5: the formerly failing nested resize case has reload 0 px, render 0.019 px, all checks true, and no unsettled measurement. Hosted Studio passes 7,889 tests, including the new regression. All reported required checks are green; one additional check was still running at my final snapshot.
No independently repeated full grid, full Studio stress run, or cancellation/crash injection. The reported load-comparison counts remain author evidence. Probe Chrome/pages closed; exported fixture/dependency links removed and read-only monitor stopped. No installs, worktrees, merge, enqueue, dispatch, or release.
Verdict: APPROVE
Reasoning: The guarded seek fixes the reproduced pre-bind GSAP error, its regression is discriminating, and exact-head accuracy plus required CI now demonstrate recovery.
— Magi (desktop-review)
jerrai-bot-heygen
left a comment
There was a problem hiding this comment.
Re-reviewed exact head 707f63aeb28ea6ca05bd7f123217bb2f05ddad01, superseding my accuracy-gate change request at 5c7df21f. The new seekBound() waits until Studio reports a positive composition duration before seeking, and openStudio() uses it on initial navigation and reload. The mocked regression enforces look-before-seek ordering; it does not alone demonstrate rendered geometry. The hosted head now supplies that missing evidence: all five accuracy shards completed successfully, and the aggregate gate reports 271 accurate against base 271, not merely green shard statuses. I inspected the shard-5 artifact for the formerly failing resize-fromto-px-r0-nested-z100-on: its reload delta is 0 px, render delta 0.019 px, and its saved/reloaded quads agree. Hosted Studio, Lint and Format also passed. This clears the prior ~90 px reload regression on the measured PR slice; it is not a claim of repeated full-grid or packaged acceptance. No merge or release by this reviewer. — Jerrai
What
Two more speedups for the Studio edit accuracy bench, stacked on #5569. Two commits:
Why
After #5569 a case still spent most of its time in
settled(), which ran 7 to 15 times per case with a fixed 500 ms window each. In a local run with the new check, the 92 stillness checks across 12 cases took 119 ms at the median (max 6 s, a sequence case waiting out a real reload). Each render also launched and closed a producer Chrome.Related work
Refs #5569 (base of this PR), #5566.
How
Stillness (
case.mjs)settled()still compares the box, the set of preview frames and (keyframed cases) a pending shadow swap against the window's first read. It now resolves after 3 animation frames in a row with no change, instead of 500 ms.file-changeevent for it has been announced (file mtime against the event's arrival). The server's event stream and the server-rendered timeline thumbnails are not counted: the stream never ends and thumbnails take seconds without changing the preview. A request whose frame was detached is dropped.EDIT_ACCURACY_STILL_MS=500restores the old fixed window exactly, with no network signal, in case the new check proves flaky on CI. Documented inpackages/studio/AGENTS.md.openStudiopolls the seek tool every 50 ms instead of 250 ms.Reuse (
render.mjs,run.mjs)--jobs 2both workers share the held browser; two renders already shared the pooled browser whenever they overlapped, so concurrency inside it is unchanged.Results
Local,
--jobs 1, mean seconds per case. The box is shared and its load average moved between 7 and 32 during these runs, so treat these as rough. Runs in the same row ran back to back.seqrepeat+ 1 keyframed, run 1seq*-none-px-r0-root-z100, run 1--grid pr --shard 1/8(34 cases),--jobs 2The single-gesture gain is large on a quiet box and small under heavy load. Sequence cases spend most of their time outside
settled()(saves, undo walks, the 3 s quiet wait for an undone sequence), so they gain less.Pass rates: on the 34-case run, 31 of 34 pass every gated metric except smoothness on both branches. Smoothness failed widely on both because of the load and is not compared here. Flips on gated metrics other than smoothness, all on sequence
undo:seqresize,seqresizeundo,seqnudgeundo,seqrepeat,seqrotatenudgeandseqplainkeyseach failed undo in at least one run on one branch, and each of the ones I re-ran also failed undo on the base branch (for exampleseqresizeundoandseqnudgeundofailed undo in 2 of 2 and 1 of 2 base re-runs). In the other directioncrop-scale-px-r0-root-z100-midfailed drop, reload and render on the base branch and passed after. I could not separate a new flake from load in these runs.Risks
EDIT_ACCURACY_STILL_MS=500is the fallback.baseline.jsonfrom these timings, the full grid should run twice on CI to see whether any case turns unstable.Test plan
settle.test.mjs(network restarts the window, frame and fixed-window holds, detached requests dropped, unannounced writes keep it busy),render.test.mjs(the held session uses the renders' launch settings and closes its page, a dead or failed hold is replaced, cache cleared per render).vitest run tests/e2e/edit-accuracy: 82 passed.oxfmt --check,oxlint,fallow audit --base origin/main,check-test-reachability(script and its tests),typecheckandtypecheck:scriptspass.packages/studio/AGENTS.md.🤖 Generated with Claude Code