Skip to content

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

Open
alwx wants to merge 15 commits intomainfrom
alwx/enhancement/multiple-ttid-ttfd
Open

Multi-instance <TimeToInitialDisplay> / <TimeToFullDisplay> coordination; a multi-signal TTID/TTFD system#6090
alwx wants to merge 15 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

🤖 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 1582d1d

Comment thread packages/core/src/js/tracing/timetodisplay.tsx Outdated
Comment thread packages/core/src/js/tracing/timetodisplay.tsx Outdated
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 thread packages/core/src/js/tracing/timetodisplay.tsx
@alwx
Copy link
Copy Markdown
Contributor Author

alwx commented May 7, 2026

@cursor review

Comment thread packages/core/src/js/tracing/timetodisplay.tsx
@alwx alwx marked this pull request as ready for review May 7, 2026 12:58
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/timeToDisplayCoordinator.ts
Comment on lines +528 to +529
const gatedReady = props.ready === undefined ? undefined : focused && props.ready;
return <Component {...props} record={focused && props.record} ready={gatedReady} />;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Bug: When a component wrapped with createTimeToFullDisplay is unfocused, passing a ready prop causes it to permanently block the aggregate TTFD signal from firing.
Severity: MEDIUM

Suggested Fix

The gatedReady logic should be changed to return undefined instead of false when the screen is unfocused. This prevents the component from opting into the coordinator registry. Change const gatedReady = props.ready === undefined ? undefined : focused && props.ready; to const gatedReady = props.ready === undefined ? undefined : focused ? props.ready : undefined;.

Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent. Verify if this is a real issue. If it is, propose a fix; if not, explain why it's
not valid.

Location: packages/core/src/js/tracing/timetodisplay.tsx#L528-L529

Potential issue: When a component created with `createTimeToInitialDisplay` or
`createTimeToFullDisplay` is on an unfocused screen, the `gatedReady` logic incorrectly
evaluates to `false` instead of `undefined` if the `ready` prop is provided. This causes
the component to register with the coordinator as a checkpoint with `ready = false`.
Because the coordinator's `computeAggregate` function returns `false` if any checkpoint
is not ready, this single unfocused component permanently blocks the aggregate readiness
for that span's TTID/TTFD, preventing the signal from firing even when all other
checkpoints on the same span become ready.

Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 1582d1d. Configure here.

//
// the idea here is that wrappers built via createTimeToFullDisplay/createTimeToInitialDisplay
// can only record TTID/TTFD on a focused screen
const gatedReady = props.ready === undefined ? undefined : focused && props.ready;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Unfocused screen's ready=false blocks new screen's coordinator

Medium Severity

When a screen loses focus, gatedReady evaluates to false (via focused && props.ready) rather than undefined. Since false !== undefined, useCoordinatedDisplay treats this as useRegistry = true and registers an active not-ready checkpoint. After navigation, getActiveSpan() returns the new screen's span, so the unfocused component registers a blocking checkpoint on the new screen's coordinator, preventing the new screen's TTFD/TTID from ever resolving. The legacy record path was passive (just didn't trigger the reporter), but the ready path is active (registers a blocker). gatedReady needs to be undefined when unfocused so the component exits the coordinator entirely.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 1582d1d. Configure here.

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