feat(engine): opt-in per-frame timing on fast-capture fallback path

Field-signal baseline: >=2 fallbacks/hr on darwin/arm64 from filter:blur
and filter:drop-shadow triggers. Fallback path perf is currently untimed,
so we can't know if the overhead is 10% or 10x. This PR adds opt-in
per-frame timing (HF_PROFILE_FALLBACK_CAPTURE=true) that emits p50/p95/p99
+ trigger reason via the observeRenderStage telemetry channel extended in
#2510. Diagnostic surface only -- no perf fix, no behavior change on
healthy paths.

Stack: PR #9 (final) of 9 (base via/escape-hatch-fallback-reproducer).

Signed-off-by: Via
This commit is contained in:
Via
2026-07-16 00:28:40 +00:00
parent 4740288050
commit e6cdf4abb1
8 changed files with 581 additions and 0 deletions
@@ -170,6 +170,18 @@ const ALLOWED_STRING_DATA_KEYS = new Set([
// from actual zero-frame stalls once capture is meant to be underway.
// Field signal ts=1784019503.
"stagePhase",
// Full-fidelity fast-capture fallback trigger — the specific reason
// drawElement gated off ("filter:blur", "filter:drop-shadow",
// "backdrop-filter", "clip-path", "at_risk_timeline", "swiftshader", …).
// Populated on the `capture_fallback_profile` checkpoint emitted by
// `fallbackCaptureProfile.ts` when the operator opts into
// `HF_PROFILE_FALLBACK_CAPTURE=true` so downstream metric consumers can
// characterize per-frame perf by the exact trigger. Complementary to
// `deGateReason`, which is the low-cardinality bucket for aggregation —
// this string preserves the fine-grained "which CSS property" for
// diagnostic reads. Sanitized like any observation message; low-cardinality
// by construction (bounded by the fallback-trigger enumeration).
"triggerReason",
]);
const RESERVED_LOG_KEYS = new Set([
"data",