Skip to content

[refactor]: add locator operation context - #3013

Open
seanmcguire12 wants to merge 4 commits into
mainfrom
add-locator-operation-context
Open

seanmcguire12 wants to merge 4 commits into
mainfrom
add-locator-operation-context

Conversation

@seanmcguire12

@seanmcguire12 seanmcguire12 commented Sep 22, 2026 •

Copy link
Copy Markdown
Member

why

a locator action needs one timeout covering all of its downstream code (eg, checking frame readiness, finding the element, & taking the action). if setup uses three seconds of a five-second timeout, the action should have two seconds left

this pr adds the shared timeout helper. later PRs will connect it to locator methods & add public timeout options.

what changed

  • added locatorOperation.ts to track the time remaining for one call. runLocatorOperation() creates it once & all nested steps share it
    • passing 0 disables the timeout
  • added run() to check the deadline before starting a step & stop waiting when time runs out. the error names the operation & the step that was still waiting.
  • added delay() so pauses between steps use the same timeout.
  • added cleanup() to attempt cleanup after a timeout, with a one-second limit on waiting. cleanup errors do not replace the original error.
  • added an optional callback to release temporary resources that arrive too late to use. commands already sent to the browser may still finish

test plan

added tests in locatorOperation.test.ts that control time & hold responses open
to verify:

  • nested steps keep the original deadline after success or failure, & timing out one call does not stop another.
  • zero disables the timeout, changing the system clock does not change the time remaining, & invalid timeout or delay values are rejected.
  • an expired call cannot start another step. a late response or error cannot resume the action.
  • resources arriving after timeout are released once; resources returned in time remain available to the caller.
  • delays stop at the deadline. long timeouts & delays are not shortened by the underlying timer's size limit.
  • timers & listeners are removed after success, failure, or timeout. timeout errors identify a step that is still waiting.
  • cleanup failures preserve the original error, & stalled cleanup neither delays the timeout response nor waits longer than its one-second allowance

Summary by cubic

Adds a shared locator operation context so a single timeout spans all steps of a locator action (frame checks, element lookup, and the action itself), replacing separate per-step deadlines.

  • runLocatorOperation() creates the context once and nested steps share its remaining budget; passing 0 disables the timeout.
  • run() checks the deadline before each step, delay() pauses within the same budget, and cleanup of late resources is attempted for one second after expiry.
  • Expiry stops waiting and may release late-arriving resources, but the timeout error always wins, even if a late command rejects.

Written for commit 1d16972. Summary will update on new commits.

Review in cubic

@seanmcguire12
seanmcguire12 added this pull request to stack #3014 September 22, 2026 23:53
@changeset-bot

changeset-bot Bot commented Sep 22, 2026 •

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: 1d16972

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@cubic-dev-ai cubic-dev-ai Bot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 2 files

Architecture diagram
sequenceDiagram
    participant Caller as Locator Caller
    participant Op as LocatorOperation
    participant Timer as Timer System
    participant Work as Work Function
    participant Cleanup as Cleanup Function
    participant Error as TimeoutError

    Note over Caller,Error: ONE shared timeout budget for the whole locator call

    Caller->>Op: runLocatorOperation({name, timeout}, work)
    alt New operation
        Op->>Op: Validate timeout (finite, >= 0)
        Op->>Timer: scheduleDeadline()
    else Existing operation
        Note over Op: Reuse parent deadline, no new timer
    end

    Op->>Op: run(name, delegate to work)
    Op->>Op: throwIfStopped() - check clock + abort signal
    Op->>Work: Execute step (frame check, element lookup, action)

    loop Each nested step
        Work->>Op: run(phase, stepWork, onLateResult?)
        Op->>Op: throwIfStopped() before dispatch
        alt Work completes before deadline
            Op-->>Work: Return result
        else Deadline expires during work
            Op->>Timer: Deadline timer fires
            Op->>Op: expireIfNeeded() - abort signal
            Op->>Error: Create TimeoutError "while {phase}"
            Op-->>Work: Abort step
        end
    end

    alt Result crossed deadline
        Op->>Cleanup: onLateResult(value)
        Cleanup->>Op: release() with 1s cap
        Op-->>Cleanup: Swallow cleanup errors
    end

    opt Multiple timer intervals needed
        loop Remaining > MAX_TIMER_MS
            Op->>Timer: setTimeout(MAX_TIMER_MS)
            Timer-->>Op: scheduleDeadline() again
        end
    end

    Op-->>Caller: Final result or TimeoutError

    Note over Op,Cleanup: Concurrent calls stay independent
    Caller->>Op: Another runLocatorOperation()
    Op->>Op: Separate AbortController + deadline
Loading

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread packages/extension/understudy/locatorOperation.ts
@seanmcguire12
seanmcguire12 force-pushed the add-locator-operation-context branch from 02c654b to c18ef88 Compare September 23, 2026 18:24
@seanmcguire12
seanmcguire12 removed this pull request from stack #3014 September 23, 2026 19:17
Base automatically changed from evals/trippyogi-fix-iframe-main-world-loading to main September 23, 2026 21:00
@seanmcguire12
seanmcguire12 force-pushed the add-locator-operation-context branch from c18ef88 to e01fbc2 Compare September 23, 2026 21:08
@seanmcguire12
seanmcguire12 added this pull request to stack #3025 September 23, 2026 21:12
@seanmcguire12
seanmcguire12 force-pushed the add-locator-operation-context branch from e01fbc2 to 1d16972 Compare September 25, 2026 22:05

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