Skip to content

perf(dom): add snapshot-only stable planning profile for noisy pages #998

@shaun0927

Description

@shaun0927

Why

Stagehand recommends deterministic environments for better cache hits: stable viewport, consistent user agent/locale, and less noisy page content. OpenChrome should not mutate real pages by deleting iframes/videos/ads as a default optimization, because those nodes may be task-relevant. However, OpenChrome can safely add an optional planning profile that filters noisy content only during serialization/observation/extraction planning.

This issue adds a conservative snapshot-only optimization that improves repeatability and output size without changing the live page DOM or click behavior.

Scope

Add an opt-in planning/snapshot profile for read/observe/extract planning paths.

In scope:

  • Configuration flag or per-call option such as planningProfile: 'stable'.
  • Snapshot/serialization filters for non-actionable noisy nodes.
  • Freeze or ignore animation-only metadata in serialized output.
  • Optional resource blocking only for local verification scripts, not as default runtime behavior.
  • Metrics showing byte/token difference between default and stable planning profiles.

Out of scope:

  • Mutating the live DOM before action execution.
  • Blocking iframes by default.
  • Network request interception as a global default.
  • Any bot-detection or stealth changes.

Proposed behavior

Supported initially in read_page mode=dom and later reusable by oc_observe if present.

Example:

{
  "tabId": "tab1",
  "mode": "dom",
  "planningProfile": "stable"
}

Stable profile may omit or normalize:

  • script/style/meta/link nodes already skipped by serializer;
  • decorative images without alt/role/link/button ancestry;
  • animation/style noise that does not affect actionability;
  • repeated ad/tracker containers only when they contain no interactive descendants;
  • volatile attributes matching known random/id/session patterns, while preserving automation-relevant IDs/data-testid names.

It must not omit:

  • inputs, buttons, links, selects, textareas;
  • iframes with visible size or accessible name;
  • elements with ARIA roles in interactive/actionable role sets;
  • text content needed for extraction unless the caller explicitly chooses interactive-only filtering.

Implementation notes

Likely files:

  • src/dom/dom-serializer.ts — add planningProfile?: 'default' | 'stable' option and stable normalization.
  • src/tools/read-page.ts — expose option and include selected profile in output metadata.
  • src/config/defaults.ts — no global default change; only constants for caps if needed.
  • tests/dom/dom-serializer*.test.ts — fixture tests.
  • tests/benchmark/* — optional benchmark extension.

No new dependency.

Acceptance criteria

  • read_page mode=dom accepts planningProfile='stable'; default behavior remains unchanged.
  • Stable profile is snapshot-only: it does not call page.evaluate to remove elements or change DOM state.
  • Stable profile preserves all actionable elements in fixtures, including buttons/inputs/links/selects and visible iframes.
  • Stable profile reduces serialized bytes by at least 20% on a noisy fixture containing decorative media/ads while returning the same actionable-node set.
  • Output metadata includes the selected planning profile.
  • Unit tests prove default and stable profiles differ only in allowed noisy/decorative content.
  • No new runtime dependency is introduced.
  • npm run build && npm test -- --runInBand tests/dom passes; broader CI remains green.

Post-merge real verification with OpenChrome

Create scripts/verify/planning-profile-stable.mjs or equivalent.

Verification flow:

  1. Serve a local noisy fixture with:
    • many decorative images;
    • repeated ad-like containers;
    • animation-heavy wrappers;
    • one login form;
    • one visible iframe with a link.
  2. Navigate to the fixture.
  3. Call read_page mode=dom planningProfile=default and record bytes plus actionable refs/names.
  4. Call read_page mode=dom planningProfile=stable and record bytes plus actionable refs/names.
    • Pass: stable bytes are at least 20% lower.
    • Pass: actionable ref/name set is identical, including iframe actionables.
  5. Execute interact on the login button after stable planning read.
    • Pass: live page still works, proving stable planning did not mutate DOM.
  6. Call javascript_tool to count original decorative nodes in the live DOM.
    • Pass: nodes still exist, proving filtering was serialization-only.
  7. Fetch metrics if token observability has landed.
    • Pass: compression/saved-token metrics show lower estimated tokens for stable profile; if not landed, script marks metrics subcheck as skipped.

Success definition

This issue is complete when stable planning reduces planning payload size on noisy pages while preserving actionability and leaving live browser behavior unchanged.

Self-review notes

  • Necessity: medium. Valuable for cache determinism and token reduction, but less urgent than cache safety/variables/metrics.
  • Direction fit: high if kept snapshot-only.
  • Scope risk: moderate if it drifts into network blocking or DOM mutation. Those are explicitly out of scope.

Curated scope, overlap handling, and verification checklist

Scope classification

  • Canonical lane: snapshot-only stable planning profile.
  • Primary deliverable: optional planningProfile: stable serialization filters that reduce noisy snapshot output without mutating the live DOM.
  • Open PR: perf(dom): add snapshot-only stable planning profile #1066 (feat/998-stable-planning-profile). Continue there; do not create duplicate implementation work.
  • Non-goal: deleting live DOM nodes, default resource blocking, changing click behavior, or hiding task-relevant elements by default.

Overlap and conflict resolution

  • Keep this limited to read/observe/extract planning snapshots; interaction semantics must remain based on real page state.
  • Coordinate with token metrics (feat(core): token and compression metrics for high-volume read tools #990) so profile impact can be measured, but metrics implementation is not this issue.
  • Avoid overlap with browser launch/profile settings unless a local verification script explicitly opts into them.

Implementation checklist

  • Add opt-in config/per-call flag such as planningProfile: stable for snapshot/serialization paths.
  • Filter or down-rank non-actionable noisy nodes and animation-only metadata in serialized output only.
  • Ensure accessibility/actionable elements remain present and locatable.
  • Add tests for stable profile on noisy fixtures, default profile unchanged, no live DOM mutation, actionable element preservation, and output-size reduction.
  • Document safe usage and warnings for pages where noisy content may be task-relevant.

Success criteria

  • Stable profile reduces noisy serialized output while leaving live DOM and click behavior unchanged.
  • default observations remain unchanged.
  • Actionable elements are not removed from the snapshot.
  • Output-size improvement is measurable on fixture pages.

Post-merge OpenChrome live verification checklist

  • Run read/observe on a noisy local fixture with default and stable profiles and compare returned chars/tokens if metrics are available.
  • Verify the live page DOM still contains filtered noisy nodes after stable snapshot.
  • Click or resolve an actionable element that appears near noisy content and verify behavior is unchanged.
  • Include before/after snapshot size and no-DOM-mutation evidence in merge notes.

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Medium priorityenhancementNew feature or requestperformancePerformance, latency, throughput, or resource-use improvement

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions