Skip to content

Architecture WS6: lazy-load maestro and provider-webdriver branches in daemon cold start #3282

Description

@thymikee

Part of #3276. Low priority.

Purpose

src/daemon.ts eagerly loads 621 of 1,435 reachable files before the first request. Two avoidable branches dominate (confirmed in built internal/daemon chunks):

  • request-binding.ts → replay-device-selection.ts pulls in all of maestro (7.3k LOC).
  • provider-device-runtimes.ts pulls in all of provider-webdriver (5.4k LOC).

Measured gain: ~10–15 ms of ~47 ms module load.

Required behavior

Make both branches load through dynamic import() at first use, or record why not (e.g. a typed reason from ADR 0027's eager-closure budget work, or an interaction-latency regression that outweighs boot).

Done when

  • Both branches are lazy, with the eager-closure budget gate updated to reflect the new baseline and planted proof that re-importing them eagerly fails the budget check; or the issue records the concrete reason not to.
  • Boot measurement before/after in the PR body (same host, multiple runs).
  • First-request latency is not measurably worse when maestro/webdriver paths are exercised (report the command and measurement).

Constraints

  • Dynamic imports must not break the daemon's build/chunking (check the built internal/daemon chunks still resolve at runtime — the size workflow is not enough).
  • No fallback shims: complete the lazy migration or don't start it.
  • Follow docs/agents/pull-requests.md (size budget, commit shape, validation).

Activity

  1. thymikee commented on Oct 7, 2026

    @thymikee
    MemberAuthor

    Recorded in #3284.

    Maestro branch: now lazy. Request binding imports @agent-device/maestro only once a replay entry resolves to a flow. The built daemon's boot set drops 109 modules (37 maestro + 72 yaml). Boot median falls 149.4→140.2 ms (n=40, interleaved). The cost now lands on the first maestro request instead, +4.9 ms once per daemon. Spawn→first maestro response is still lower: 543.3→536.6 ms (n=30). src/daemon.ts is now a hub in the eager-closure budget.

    provider-webdriver branch: not made lazy. The reason is concrete. startDaemonRuntime awaits createDaemonProviderRuntimeComposition(env) → providerWebDriver.createDefaultRuntimes(env) before the server listens (src/daemon/server/daemon-runtime.ts:361, listen at :602). First use is boot. A daemon-side import() would drop the static closure count but load the same chunk in the same boot phase, so the counter would improve and the runtime wouldn't. With every other boot chunk preloaded, the built provider-webdriver chunk evaluates in about 1.4 ms. That is the upper bound on what moving the boundary into the package could save: CloudWebDriverRuntime's constructor would have to build its session and deployment managers lazily, behind the first lease. That gain doesn't justify making the provider runtime construction-lazy.

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

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions