Skip to content

Commit 6d3895f

Browse files
antonisclaude
andcommitted
fix(tracing): Use actual span end timestamp for frames.delay in TTID/TTFD
Pass the intended span end timestamp into captureEndFramesAndAttachToSpan instead of falling back to Date.now(). The function runs before span.end() is called, so spanToJSON(span).timestamp is always undefined, causing the delay calculation to include frame data after the span semantically ended. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent ab915eb commit 6d3895f

1 file changed

Lines changed: 8 additions & 7 deletions

File tree

packages/core/src/js/tracing/timetodisplay.tsx

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -203,9 +203,10 @@ export function startTimeToFullDisplaySpan(
203203
}
204204
fullDisplaySpan.setStatus({ code: SPAN_STATUS_ERROR, message: 'deadline_exceeded' });
205205

206-
captureEndFramesAndAttachToSpan(fullDisplaySpan).then(() => {
206+
const fullDisplayEndTimestamp = spanToJSON(initialDisplaySpan).timestamp;
207+
captureEndFramesAndAttachToSpan(fullDisplaySpan, fullDisplayEndTimestamp).then(() => {
207208
debug.log(`[TimeToDisplay] span ${fullDisplaySpan.spanContext().spanId} updated with frame data.`);
208-
fullDisplaySpan.end(spanToJSON(initialDisplaySpan).timestamp);
209+
fullDisplaySpan.end(fullDisplayEndTimestamp);
209210
setSpanDurationAsMeasurement('time_to_full_display', fullDisplaySpan);
210211
}).catch(() => {
211212
debug.warn(`[TimeToDisplay] Failed to capture end frames for full display span (${fullDisplaySpan.spanContext().spanId}).`);
@@ -265,7 +266,7 @@ export function updateInitialDisplaySpan(
265266
return;
266267
}
267268

268-
captureEndFramesAndAttachToSpan(span).then(() => {
269+
captureEndFramesAndAttachToSpan(span, frameTimestampSeconds).then(() => {
269270
span.end(frameTimestampSeconds);
270271
span.setStatus({ code: SPAN_STATUS_OK });
271272
debug.log(`[TimeToDisplay] ${spanToJSON(span).description} span updated with end timestamp and frame data.`);
@@ -322,8 +323,8 @@ function updateFullDisplaySpan(frameTimestampSeconds: number, passedInitialDispl
322323
return;
323324
}
324325

325-
captureEndFramesAndAttachToSpan(span).then(() => {
326-
const endTimestamp = initialDisplayEndTimestamp > frameTimestampSeconds ? initialDisplayEndTimestamp : frameTimestampSeconds;
326+
const endTimestamp = initialDisplayEndTimestamp > frameTimestampSeconds ? initialDisplayEndTimestamp : frameTimestampSeconds;
327+
captureEndFramesAndAttachToSpan(span, endTimestamp).then(() => {
327328

328329
if (initialDisplayEndTimestamp > frameTimestampSeconds) {
329330
debug.warn('[TimeToDisplay] Using initial display end. Full display end frame timestamp is before initial display end.');
@@ -466,7 +467,7 @@ async function captureStartFramesForSpan(spanId: string): Promise<void> {
466467
/**
467468
* Captures end frames and attaches frame data to span
468469
*/
469-
async function captureEndFramesAndAttachToSpan(span: Span): Promise<void> {
470+
async function captureEndFramesAndAttachToSpan(span: Span, spanEndTimestampSeconds?: number): Promise<void> {
470471
if (!NATIVE.enableNative) {
471472
return;
472473
}
@@ -488,7 +489,7 @@ async function captureEndFramesAndAttachToSpan(span: Span): Promise<void> {
488489
const spanStartTimestamp = spanToJSON(span).start_timestamp;
489490
if (spanStartTimestamp) {
490491
try {
491-
const endTimestamp = spanToJSON(span).timestamp || Date.now() / 1000;
492+
const endTimestamp = spanEndTimestampSeconds || spanToJSON(span).timestamp || Date.now() / 1000;
492493
const framesDelay = await NATIVE.fetchNativeFramesDelay(spanStartTimestamp, endTimestamp);
493494
if (framesDelay != null) {
494495
span.setAttribute('frames.delay', framesDelay);

0 commit comments

Comments
 (0)