Repository navigation
perf: settle only on visible finite animations; collect testIds in one call - #65
Draft
cryptotavares wants to merge 3 commits into
Draft
cryptotavares wants to merge 3 commits into
cryptotavares wants to merge 3 commits into
Conversation
Tickets P1-10 + P1-12. - Animation settle: wait only for running, finite animations whose target element is in the viewport (spinners, shimmer and other infinite or off-screen animations no longer hold the observation). Cap 1000 ms (was 3000 ms). Hidden pages poll with setTimeout (rAF does not fire). - collectTestIds: one in-page call instead of getAttribute + isVisible + textContent per element. Same output shape and order; visibility follows Playwright's isVisible (non-empty box, visibility visible, display: contents via children; opacity 0 counts as visible). Times out after 5 s and falls back to the old per-element locator loop on any failure. - Both in-page functions run in a CDP isolated world of the main frame (Page.createIsolatedWorld + Runtime.callFunctionOn), which shares the DOM but not page globals, so LavaMoat scuttling cannot break them. One session and world per page, recreated once after navigation. Extension bench (p50): list-testids toolMs 53 -> 1; home click observationMs 562 -> 515; first Send click observation 8003 ms (timed out, no testIds) -> 43 ms.
cryptotavares
added this pull request to stack #63
October 24, 2026 10:31
This was referenced Oct 24, 2026
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stack context: mm CLI v2, Phase 1, P1-10 + P1-12, combined in one PR. Base:
cryptotavares/mmcli-p1-08-abort-refs; review #64 first. Followed by #66.Problem
Browser observations wait for every running animation, including spinners that never finish. The old main-world check also depends on globals that LavaMoat can restrict. Hidden tabs do not provide the animation frames that the check needs.
TestId collection adds three Playwright calls per element:
getAttribute,isVisible, andtextContent. Extension home therefore needs many round trips before the accessibility snapshot starts.These costs share the observation budget. The historical proof below records a first Send observation that times out without testIds. This PR changes the browser collection boundary used by observations and
PlaywrightPlatformDriver.getTestIds.Solution
Keep browser orchestration in the daemon. Move DOM inspection into self-contained functions that execute in the main frame's isolated world.
flowchart TD A[Browser observation] --> B{Read-only or discovery tool?} B -->|no| C[Wait for finite, in-viewport animations] B -->|yes| D[Collect testIds in cached isolated world] C --> D D -->|success| E[Map items to existing output shape] D -->|failure or timeout| F[Collect testIds through locator fallback] E --> G[Collect accessibility tree] F --> G G --> H[Return observation] classDef new fill:#fff3cd,stroke:#d39e00 class C,D,E,F newYellow boxes are new.
callInIsolatedWorldowns the CDP session and execution context. AWeakMapcaches them per page. Steady-state calls send oneRuntime.callFunctionOnrequest. Protocol or session failures clear the matching cache entry and retry once. In-page exceptions propagate without a retry.The isolated world shares the DOM but has separate globals. Page functions travel as source text, so they cannot import helpers or capture module state. Their helpers stay inside each function. The source wrapper supplies
__namefor keepNames-transformed functions; VM tests check the serialization boundary.discovery.tsowns the failure policy. Animation timeouts and unreadable pages end the wait. TestId call failures and timeouts use the locator fallback. The server still checks its abort signal between observation stages.What changes
tagstayselementCollection includes hidden testIds with
visible: false. Visibility follows Playwright's rules, includingdisplay: contents, non-empty boxes, and computedvisibility. Zero opacity and off-screen position do not hide an otherwise visible item.The collector visits document matches before open shadow-root matches. It skips empty testIds without consuming the limit. Text remains trimmed and capped at 100 characters; null text maps to
undefinedat the daemon boundary.Decisions for reviewers
Review guide
Read the files in this order:
src/server/create-server.tssnapshotBrowserkeeps category-based settling, collection order, and abort checkpoints.src/tools/utils/constants.tssrc/tools/utils/cdp.tssrc/tools/utils/in-page.tssrc/tools/utils/discovery.tssrc/tools/utils/{cdp,in-page,discovery}.test.ts,src/server/create-server.test.tsTesting
50eb3962b30ee8f5e2605dfcf307417e0282f560:CI=true yarn vitest run src/tools/utils/cdp.test.ts src/tools/utils/in-page.test.ts src/tools/utils/discovery.test.ts src/server/create-server.test.ts src/platform/playwright-driver.test.ts src/tools/discovery-tools.test.ts --coverage.enabled=false --maxWorkers=2 --minWorkers=1passes: 6 files, 317 tests.yarn lintpasses.yarn tsc --project tsconfig.build.json --noEmitpasses for production sources.yarn tsc --project tsconfig.json --noEmitfails at the remote head with 11 test diagnostics. One is the newin-page.test.ts:728type predicate (TS2677); ten come from inherited test code.EACCESlog from its read-only log-directory fixture and passes.ProofandUnit testssections below retain the original historical evidence. These fresh checks do not repeat the live browser benchmarks or full coverage run.Breaking changes
None. The constants are internal. Observations may now be taken while an infinite or off-screen animation is still running; that is intended.
Consumer impact
test/e2e/playwright/llm-workflow/tests/llm-workflow/Proof
Tested with a yalc build of this branch in the Extension (e2e build, headless). I ran a fresh before/after bench back to back: before = #64 (7d0c565), after = this branch. Every bench has 5 runs, and the 1-minute host load was 6–9. After a review round I re-checked the final commit (50eb396) and got the same numbers.
list-testidson home, toolMs p50/p95 (44 items)list-testidsJSON, home + unlocktextvalues, which also changes between two runs of the same buildThe remaining ~515 ms on home is the accessibility-tree snapshot:
get-state --observe fulltakes ~509 ms without any settle. The settle and testIds now add about 6 ms together. P1-14 targets that snapshot.Known gap: the locator fallback logs only through
debugWarn, so it is visible only withDEBUG=true. In the recheck it never ran: everylist_testidstook ~1–2 ms; the fallback takes ~50 ms.Unit tests
New tests:
in-page.test.ts:vmcontext, so a stray import or closure fails the test;toString()has no bundler helpers other than__name;display: contents,visibility, zero box), text, limit and shadow-root order.cdp.test.ts: session/world caching, retry after navigation, in-page exceptions, timeout.discovery.test.ts: the single call, plus fallback to locators on failure and on timeout.