feat(engine): measure live DOM size on every render, not just probed ones

The short-comp routing gate can only read a live element count when a
probe session exists, and the first v0.7.83 data shows that is far rarer
than estimated: 17% of renders (86/503), not the ">=28%" the video-presence
proxy suggested. The other 83% fall back to a static source scan, which
is exactly blind to the shape that motivated the live count — small
markup, thousands of script-created nodes.

That leaves the fleet element-count distribution unknowable for most
renders, and the observed distribution is already surprising: p99 ~900,
max 1,420 against a 2,500 ceiling calibrated on 7k/20k/40k synthetic
nodes. Either the ceiling is close to irrelevant, or the large-DOM tail
is hiding in the 83% we cannot see. Both readings change what PR B
should do, and neither is decidable from probed renders alone (they are
a biased sample — they got a probe *because* they carry media or
unresolved compositions).

So measure it where every render already goes: capture-session init.
`collectSessionInitTelemetry` gains a querySelectorAll("*") count beside
the tween count it already collects, riding the same channel to
`observability_init_element_count`. This is observational only — capture
has begun, far too late to route on — and it deliberately does not feed
the gate. It answers the distribution question the gate cannot.

Coverage for this channel is proven rather than assumed: the tween-count
fix that shipped in v0.7.83 took the clamped-parallel bucket from 0/272
renders to 217/217, and 23.1% -> 100% overall.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Vance Ingalls
2026-07-29 22:55:12 -07:00
co-authored by Claude Opus 5
parent 5244dde5f1
commit d74afc7b7d
8 changed files with 99 additions and 17 deletions
+22 -3
View File
@@ -119,6 +119,8 @@ export interface CaptureSession {
initTelemetry?: {
initDurationMs: number;
tweenCount: number;
/** Live DOM element count at end of init — observational; see collectSessionInitTelemetry. */
elementCount: number;
};
capturePerf: {
frames: number;
@@ -406,8 +408,24 @@ function appendBrowserDiagnostic(session: CaptureSession, text: string): void {
async function collectSessionInitTelemetry(
page: Page,
initStart: number,
): Promise<{ initDurationMs: number; tweenCount: number }> {
): Promise<{ initDurationMs: number; tweenCount: number; elementCount: number }> {
const initDurationMs = Date.now() - initStart;
// Live DOM size, measured once the init sequence has completed so
// script-generated elements are present. This is the SAME quantity the
// short-comp routing gate wants, but measured here it is observational
// only — capture has already started, so it is far too late to route on.
// Its job is coverage: the routing gate can only read a live count on the
// ~17% of renders that get a probe session, which leaves the fleet
// element-count distribution unknowable for the rest (and hides exactly
// the dangerous shape — small source markup, huge runtime DOM). Every
// render reaches this path, so the distribution becomes readable even
// where the gate stays blind.
let elementCount = 0;
try {
elementCount = await page.evaluate(() => document.querySelectorAll("*").length);
} catch {
elementCount = 0;
}
let tweenCount = 0;
try {
tweenCount = await page.evaluate(() => {
@@ -431,7 +449,7 @@ async function collectSessionInitTelemetry(
} catch {
tweenCount = 0;
}
return { initDurationMs, tweenCount };
return { initDurationMs, tweenCount, elementCount };
}
async function recordSessionInitTelemetry(
@@ -442,7 +460,7 @@ async function recordSessionInitTelemetry(
session.initTelemetry = telemetry;
appendBrowserDiagnostic(
session,
`[FrameCapture:INIT] complete initDurationMs=${telemetry.initDurationMs} tweenCount=${telemetry.tweenCount}`,
`[FrameCapture:INIT] complete initDurationMs=${telemetry.initDurationMs} tweenCount=${telemetry.tweenCount} elementCount=${telemetry.elementCount}`,
);
}
@@ -3788,6 +3806,7 @@ export function getCapturePerfSummary(session: CaptureSession): CapturePerfSumma
subTimelineWaitOutcome: session.subTimelineWaitOutcome,
initDurationMs: session.initTelemetry?.initDurationMs,
initTweenCount: session.initTelemetry?.tweenCount,
initElementCount: session.initTelemetry?.elementCount,
warnings: cloneCaptureWarnings(session.warnings),
staticDedupReused: session.staticDedupCount ?? 0,
staticDedupEnabled: session.staticDedupEnabled ?? false,