Skip to content

Multi-instance <TimeToInitialDisplay> / <TimeToFullDisplay> coordination; a multi-signal TTID/TTFD system#6090

Draft
alwx wants to merge 7 commits intomainfrom
alwx/enhancement/multiple-ttid-ttfd
Draft

Multi-instance <TimeToInitialDisplay> / <TimeToFullDisplay> coordination; a multi-signal TTID/TTFD system#6090
alwx wants to merge 7 commits intomainfrom
alwx/enhancement/multiple-ttid-ttfd

Conversation

@alwx
Copy link
Copy Markdown
Contributor

@alwx alwx commented May 5, 2026

📢 Type of change

  • Bugfix
  • New feature
  • Enhancement
  • Refactoring

📜 Description

Somthing that was requested by our customers: when a screen has multiple async data sources, you can now mount one <TimeToFullDisplay> per source — the TTID/TTFD will get recorded only when all the sources report ready. That makes it possible to use TTID/TTFD when the screen comes with a bunch of individual components to handle not so simple real-world scenarios.

For example, a screen might have:

  1. A header component that fetches user profile data
  2. A main content area pulling from one API
  3. A sidebar or secondary section hitting a completely different service
  4. Nested child components several levels deep that each manage their own data fetching

All of these load independently, at different times, and the screen isn't actually fully displayed until every one of them has resolved and rendered. With the current SDK, the only way to handle this is to hoist state management above all of these components, track which ones have finished loading, and only fire the TTFD signal once everything reports in. That's a significant amount of orchestration code that really belongs in the SDK itself.

What we're doing here is basically making it work with multiple TTID/TTFD components to handle multiple signals coming from different sources.

The docs will be updated soon.

💚 How did you test it?

Tests were added.

📝 Checklist

  • I added tests to verify changes
  • No new PII added or SDK only sends newly added PII if sendDefaultPII is enabled
  • I updated the docs if needed.
  • I updated the wizard if needed.
  • All tests passing
  • No breaking changes

🔮 Next steps

@alwx alwx self-assigned this May 5, 2026
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 5, 2026

Semver Impact of This PR

None (no version bump detected)

📋 Changelog Preview

This is how your changes will appear in the changelog.
Entries from this PR are highlighted with a left border (blockquote style).


  • Multi-instance <TimeToInitialDisplay> / <TimeToFullDisplay> coordination; a multi-signal TTID/TTFD system by alwx in #6090
  • build(core): Add public API surface tracking with api-extractor by antonis in #6093
  • chore(deps): bump axios from 1.15.0 to 1.16.0 by dependabot in #6091
  • ci: Add workflow to notify issues when fix is released by antonis in #6089
  • ci: Add Danger check to warn about auth token handling changes by antonis in #6087
  • Fix PNPM iOS Upload Debug Symbol fail in EAS Build by alwx in #6086
  • chore(deps): update Sentry Android Gradle Plugin to v6.6.0 by github-actions in #6085
  • fix(e2e): Remove flaky iOS replay assertion from captureReplay test by antonis in #6072
  • chore(deps): bump github/codeql-action from 4.35.2 to 4.35.3 by dependabot in #6078
  • fix: Prevent shell injection vulnerability in GitHub Actions workflow by fix-it-felix-sentry in #6077
  • chore(deps): update Maestro to v2.5.1 by github-actions in #6075

🤖 This preview updates automatically when you update the PR.

@alwx alwx marked this pull request as ready for review May 5, 2026 09:58
@alwx alwx force-pushed the alwx/enhancement/multiple-ttid-ttfd branch from 97bd1be to cb268c8 Compare May 5, 2026 10:00
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 5, 2026

Fails
🚫 Pull request is not ready for merge, please add the "ready-to-merge" label to the pull request

Generated by 🚫 dangerJS against a420720

Comment thread packages/core/src/js/tracing/timetodisplay.tsx Outdated
Comment thread packages/core/src/js/tracing/timetodisplay.tsx
Comment thread packages/core/src/js/tracing/timetodisplay.tsx Outdated
@alwx alwx removed request for antonis and lucas-zimerman May 5, 2026 10:03
Comment thread packages/core/src/js/tracing/timetodisplay.tsx
Comment thread packages/core/src/js/tracing/timetodisplay.tsx
@alwx alwx marked this pull request as draft May 5, 2026 10:04
Comment thread packages/core/src/js/tracing/timeToDisplayCoordinator.ts
Comment thread packages/core/src/js/tracing/timetodisplay.tsx
Comment thread packages/core/src/js/tracing/timetodisplay.tsx
@alwx
Copy link
Copy Markdown
Contributor Author

alwx commented May 5, 2026

Moved it back to draft because multi-instance coordination needs to be handled more carefully.

Comment on lines +195 to +201
useEffect(() => {
if (!parentSpanId || !useRegistry) {
return undefined;
}
return registerCheckpoint(kind, parentSpanId, checkpointId, localReady);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [kind, parentSpanId, useRegistry, checkpointId]);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unmounting a not-ready checkpoint can flip aggregate to true, causing premature TTID/TTFD

When a registry-mode component unmounts, the cleanup at line 199 calls the unregister returned by registerCheckpoint, which deletes the checkpoint and calls reevaluate. If the unmounting checkpoint was the only not-ready one, removing it flips the aggregate to true, immediately notifying peers that 'all are ready' even though that source never actually became ready. A conditionally-rendered loading section that unmounts before its data resolves will incorrectly satisfy the coordination, recording an incomplete display.

Verification

Read registerCheckpoint's returned unregister fn in timeToDisplayCoordinator.ts (lines 93-102): it deletes the checkpoint then calls reevaluate(e). computeAggregate returns true when all remaining checkpoints are ready; thus removing the only not-ready entry flips the cached aggregate to true and notifies listeners. No guard exists for this scenario.

Identified by Warden find-bugs · GW4-XFB

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant