( session: Composition, hfId: string | null | undefined, ops: PatchOperation[], sourceContent?: string, )
| 258 | * call exactly as it started. |
| 259 | */ |
| 260 | export function runResolverShadow( |
| 261 | session: Composition, |
| 262 | hfId: string | null | undefined, |
| 263 | ops: PatchOperation[], |
| 264 | sourceContent?: string, |
| 265 | ): void { |
| 266 | if (!STUDIO_SDK_RESOLVER_SHADOW_ENABLED) return; |
| 267 | if (!hfId) return; |
| 268 | try { |
| 269 | const mismatches = sdkResolverShadowCheck(session, hfId, ops, sourceContent); |
| 270 | // Emit only on divergence — parity is silent, matching recordResolverParity |
| 271 | // and recordAnimationResolverParity. Otherwise this fires a PostHog event on |
| 272 | // every style/text/attr edit (the editor's chattiest path) at default-ON. |
| 273 | if (mismatches.length === 0) return; |
| 274 | const isElementNotFound = mismatches.some((m) => m.kind === "element_not_found"); |
| 275 | const strictCount = |
| 276 | isElementNotFound && sourceContent !== undefined |
| 277 | ? countHfIdInSource(sourceContent, hfId) |
| 278 | : undefined; |
| 279 | trackStudioEvent("sdk_resolver_shadow", { |
| 280 | hfId, |
| 281 | // sessionElementCount > 0 + element_not_found = runtime-only element; |
| 282 | // sessionElementCount === 0 = session is empty/broken (actionable). |
| 283 | sessionElementCount: session.getElements().length, |
| 284 | // Count of data-hf-id="<id>" occurrences in source for an emitted |
| 285 | // element_not_found. >1 = duplicate ids → resolver picked the wrong |
| 286 | // instance; =1 = single static node the SDK parse dropped (foreign-content |
| 287 | // exclusion / sub-comp inlining gap); =0 = the runtime-node filter above |
| 288 | // uses a loose substring match (biased toward keeping signal) while this |
| 289 | // count uses a strict attribute match — see sourceLooseMatchOnly below. |
| 290 | ...(strictCount !== undefined ? { sourceHfIdCount: strictCount } : {}), |
| 291 | // Loose suppression check matched (kept this event) but the strict |
| 292 | // attribute count came back 0 — see the sourceHfIdCount comment above. |
| 293 | ...(strictCount === 0 ? { sourceLooseMatchOnly: true } : {}), |
| 294 | mismatchCount: mismatches.length, |
| 295 | mismatches: JSON.stringify(redactMismatches(mismatches)), |
| 296 | }); |
| 297 | } catch { |
| 298 | // never propagate from the shadow path |
| 299 | } |
| 300 | } |
| 301 | |
| 302 | /** |
| 303 | * Record element-resolution parity for an element-targeted op WITHOUT |
no test coverage detected