Back to Plate

Slate DOM strategy needs production RUM metrics

docs/solutions/performance-issues/2026-05-03-slate-rendering-strategy-needs-production-rum-metrics.md

53.0.64.1 KB
Original Source

Slate DOM strategy needs production RUM metrics

Problem

DOM strategy work can look good in local benchmark artifacts while production users still hit the wrong cohort, strategy, or native-behavior tradeoff. The runtime needs a small app-facing metric seam so products can tag RUM or Datadog rows with the same facts used in lab proof.

Symptoms

  • Benchmarks tracked DOM nodes, editable descendants, heap, and coverage boundaries, but apps had no equivalent runtime callback.
  • Virtualized and partial-DOM modes could not be compared honestly in production dashboards without custom DOM scraping.
  • Phase 8 virtualization showed good ready/select-all rows but bad 50000-block edit lanes, which made a production cohort split mandatory.
  • After the public shell option was cut, shellCount, shellAggressiveBoundaryCount, and 'shell' metric enum values still leaked the old API vocabulary.

What Didn't Work

  • Treating benchmark artifacts as enough. They are lab evidence, not production observability.
  • Mixing partial-DOM and virtualized timings into default staged rows. That hides degraded-mode behavior under a better-looking aggregate.
  • Adding a fake Datadog integration in raw Slate. Slate should expose metrics; apps own where those metrics are sent.
  • Removing the public prop but leaving shell-specific metrics. That makes the docs cleaner while dashboards and agents still learn the wrong API.

Solution

Add an Editable callback that reports DOM strategy surface metrics after commit:

tsx
<Editable
  domStrategy="staged"
  onDOMStrategyMetrics={(metrics) => {
    datadogRum.addAction('slate.dom_strategy.surface', metrics)
  }}
/>

The metric payload includes:

  • document cohort and size;
  • requested and effective DOM strategy;
  • mounted and pending group counts;
  • mounted and pending top-level counts;
  • native surface completion;
  • DOM coverage boundary counts by reason;
  • visible DOM node count;
  • editable descendant count.

In Slate v2 this lands through onDOMStrategyMetrics and exported EditableDOMStrategyMetrics. Tests cover staged and virtualized surfaces.

When cutting a public DOM mode, audit the metric payload too:

  • remove mode-specific public counters such as shellCount;
  • rename mode-specific boundary counters to mechanism-level names such as aggressiveDomCoverageBoundaryCount;
  • expose internal incomplete DOM as partial-dom, not as the private implementation name;
  • keep internal coverage tests behind one internal test helper instead of widening the public domStrategy prop type.

Why This Works

The callback keeps raw Slate unopinionated while giving products the exact tags they need for dashboards. Benchmarks still own lab proof; RUM owns production drift. Keeping the DOM strategy fields separate prevents partial-DOM or virtualized stress rows from polluting default staged-rendering claims.

Prevention

  • Every DOM strategy that changes DOM coverage needs a production metric seam, not only a benchmark row.
  • Dashboard tags should include interaction name, cohort, document size, requested DOM strategy, effective DOM strategy, boundary count, visible DOM count, editable descendant count, custom renderer flag, browser, mobile/desktop, IME, and release.
  • Keep degraded strategies separate in dashboards. If a strategy changes browser find, screen-reader traversal, selection, copy, paste, IME, or mobile semantics, aggregate charts must not hide that.
  • Do not stabilize an experimental strategy just because ready time is good. Edit interactions and native behavior rows decide release posture.
  • Public API hard-cuts must include props, docs, examples, URL params, metrics payloads, and surface-contract tests. Otherwise the removed API lives on in dashboards and agent-facing examples.