test(e2e): Group collectStreamedSpans by trace - #23912

Merged
andreiborza merged 1 commit into
developfrom
ab/js-3482/collect-streamed-spans
Sep 2, 2026
Merged

test(e2e): Group collectStreamedSpans by trace#23912
andreiborza merged 1 commit into
developfrom
ab/js-3482/collect-streamed-spans

Conversation

@andreiborza

@andreiborzaandreiborza commented Sep 2, 2026

Copy link
Copy Markdown
Member

What

Groups the spans collectStreamedSpans accumulates by trace, so its predicate sees one trace at a time instead of a flat pile, and it resolves with only that trace's spans. Also re-exports SerializedStreamedSpan so specs can type their span helpers.

Why

Spans are buffered per trace and flushed on a timer, so a previous test's spans can still be arriving when the next one starts collecting. A test asserting on one request's children could therefore mix in an earlier page load's spans, or have its wait satisfied by them before its own spans arrived. Every trace is evaluated as a candidate, so a leftover trace that never satisfies the predicate cannot hold up the one that does.

Note this scopes a result to a single trace, it does not identify which trace: when several tests exercise the same route, the predicate still has to name something unique to the request under test.

Split out of the React Router porting stack because it is useful on its own, and other span streaming ports can drop their hand-rolled trace_id filtering once it lands.

It accumulated every span envelope into a single array, so a test asserting on
one request's children could mix in spans from an earlier page load's trace, or
have its wait satisfied by them. Spans are bucketed per trace now and the
predicate sees one trace at a time, so it resolves with a coherent set.
Every trace is evaluated as a candidate, so a leftover trace that never satisfies
the predicate cannot hold up the one that does. Note this scopes a result to a
single trace, it does not identify which trace: when several tests exercise the
same route, the predicate still has to name something unique to the request under
test.
Also re-exports `SerializedStreamedSpan`, which specs need to type their span
helpers.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@linear-code

Copy link
Copy Markdown

JS-3482

@github-actions

Copy link
Copy Markdown
Contributor

size-limit report 📦

PathSize% ChangeChange
@sentry/browser28.57 kB--
@sentry/browser - with treeshaking flags26.94 kB--
@sentry/browser - with treeshaking flags tracing without tracing26.83 kB--
@sentry/browser (incl. Tracing)48.87 kB--
@sentry/browser (incl. Tracing + Span Streaming)48.88 kB--
@sentry/browser (incl. Tracing, Profiling)51.8 kB--
@sentry/browser (incl. Tracing, Replay)88.36 kB--
@sentry/browser (incl. Tracing, Replay) - with treeshaking flags77.76 kB--
@sentry/browser (incl. Tracing, Replay with Canvas)93.05 kB--
@sentry/browser (incl. Tracing, Replay, Feedback)106.02 kB--
@sentry/browser (incl. Feedback)46.06 kB--
@sentry/browser (incl. sendFeedback)33.64 kB--
@sentry/browser (incl. FeedbackAsync)38.74 kB--
@sentry/browser (incl. Metrics)29.52 kB--
@sentry/browser (incl. Logs)29.81 kB--
@sentry/browser (incl. Metrics & Logs)30.45 kB--
@sentry/react30.32 kB--
@sentry/react (incl. Tracing)51.08 kB--
@sentry/vue35.74 kB--
@sentry/vue (incl. Tracing)51.14 kB--
@sentry/svelte28.6 kB--
CDN Bundle30.36 kB--
CDN Bundle (incl. Tracing)49.52 kB--
CDN Bundle (incl. Logs, Metrics)32.59 kB--
CDN Bundle (incl. Tracing, Logs, Metrics)51.43 kB--
CDN Bundle (incl. Replay, Logs, Metrics)73.19 kB--
CDN Bundle (incl. Tracing, Replay)87.01 kB--
CDN Bundle (incl. Tracing, Replay, Logs, Metrics)88.88 kB--
CDN Bundle (incl. Tracing, Replay, Feedback)92.94 kB--
CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics)94.84 kB--
CDN Bundle - uncompressed89.97 kB--
CDN Bundle (incl. Tracing) - uncompressed147.58 kB--
CDN Bundle (incl. Logs, Metrics) - uncompressed96.27 kB--
CDN Bundle (incl. Tracing, Logs, Metrics) - uncompressed153.27 kB--
CDN Bundle (incl. Replay, Logs, Metrics) - uncompressed225.43 kB--
CDN Bundle (incl. Tracing, Replay) - uncompressed267.07 kB--
CDN Bundle (incl. Tracing, Replay, Logs, Metrics) - uncompressed272.75 kB--
CDN Bundle (incl. Tracing, Replay, Feedback) - uncompressed280.77 kB--
CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics) - uncompressed286.44 kB--
@sentry/nextjs (client)53.7 kB--
@sentry/sveltekit (client)49.3 kB--
@sentry/core/server40.74 kB--
@sentry/core/browser13.42 kB--
@sentry/node124.05 kB+0.02%+22 B 🔺
@sentry/node/import (ESM hook with diagnostics-channel injection)81.51 kB--
@sentry/node - without tracing88.3 kB+0.03%+21 B 🔺
@sentry/node - without channel injection103.36 kB+0.03%+22 B 🔺
@sentry/aws-serverless96.66 kB+0.03%+25 B 🔺
@sentry/cloudflare (withSentry) - minified201.23 kB--
@sentry/cloudflare (withSentry)500.94 kB--

View base workflow run

@andreiborza
andreiborza merged commit 7fd2c1b into developSep 2, 2026
256 checks passed
JPeer264 added a commit that referenced this pull request Sep 2, 2026
Ports `cloudflare-orchestrion-mysql` to span streaming.
Streamed mysql spans are named by the low-cardinality query summary,
which is `SELECT` for both statements in this app, so the spec locates
the spans by their `db.query.text` attribute and pins the `SELECT` name
separately. `collectStreamedSpans` groups spans by trace since #23912,
so the predicate only has to see the `/test-mysql` segment and the `db`
spans; the nested-query test keeps proving the async context restore by
requiring both spans in that trace.
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
JPeer264 added a commit that referenced this pull request Sep 2, 2026
Ports `cloudflare-agent` to span streaming. The gen_ai assertions were
already on streamed spans; the remaining `waitForTransaction` calls are
replaced.
- The worker and the Agent Durable Object both emit a `GET` segment for
the same URL. The DO segment is picked by `url.path` plus a defined
`parent_span_id` (the worker propagates its trace over the RPC binding),
same discriminator the old spec used.
- The three surviving storage spans are children of the `greet` rpc
span, so they are selected by `parent_span_id` and ordered by
`start_timestamp`; the count-based filter proof is unchanged.
- gen_ai-to-segment relations rely on `collectStreamedSpans` grouping by
trace (#23912): the collect finishes once the owning segment has
arrived, so no manual `trace_id` matching is needed.
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Sign up for freeto 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.

2 participants

@andreiborza@chargome
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

test(e2e): Group collectStreamedSpans by trace - #23912

Merged
andreiborza merged 1 commit into
developfrom
ab/js-3482/collect-streamed-spans
Sep 2, 2026
Merged

test(e2e): Group collectStreamedSpans by trace#23912
andreiborza merged 1 commit into
developfrom
ab/js-3482/collect-streamed-spans

Conversation

@andreiborza

@andreiborzaandreiborza commented Sep 2, 2026

Copy link
Copy Markdown
Member

What

Groups the spans collectStreamedSpans accumulates by trace, so its predicate sees one trace at a time instead of a flat pile, and it resolves with only that trace's spans. Also re-exports SerializedStreamedSpan so specs can type their span helpers.

Why

Spans are buffered per trace and flushed on a timer, so a previous test's spans can still be arriving when the next one starts collecting. A test asserting on one request's children could therefore mix in an earlier page load's spans, or have its wait satisfied by them before its own spans arrived. Every trace is evaluated as a candidate, so a leftover trace that never satisfies the predicate cannot hold up the one that does.

Note this scopes a result to a single trace, it does not identify which trace: when several tests exercise the same route, the predicate still has to name something unique to the request under test.

Split out of the React Router porting stack because it is useful on its own, and other span streaming ports can drop their hand-rolled trace_id filtering once it lands.

It accumulated every span envelope into a single array, so a test asserting on
one request's children could mix in spans from an earlier page load's trace, or
have its wait satisfied by them. Spans are bucketed per trace now and the
predicate sees one trace at a time, so it resolves with a coherent set.
Every trace is evaluated as a candidate, so a leftover trace that never satisfies
the predicate cannot hold up the one that does. Note this scopes a result to a
single trace, it does not identify which trace: when several tests exercise the
same route, the predicate still has to name something unique to the request under
test.
Also re-exports `SerializedStreamedSpan`, which specs need to type their span
helpers.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@linear-code

Copy link
Copy Markdown

JS-3482

@github-actions

Copy link
Copy Markdown
Contributor

size-limit report 📦

PathSize% ChangeChange
@sentry/browser28.57 kB--
@sentry/browser - with treeshaking flags26.94 kB--
@sentry/browser - with treeshaking flags tracing without tracing26.83 kB--
@sentry/browser (incl. Tracing)48.87 kB--
@sentry/browser (incl. Tracing + Span Streaming)48.88 kB--
@sentry/browser (incl. Tracing, Profiling)51.8 kB--
@sentry/browser (incl. Tracing, Replay)88.36 kB--
@sentry/browser (incl. Tracing, Replay) - with treeshaking flags77.76 kB--
@sentry/browser (incl. Tracing, Replay with Canvas)93.05 kB--
@sentry/browser (incl. Tracing, Replay, Feedback)106.02 kB--
@sentry/browser (incl. Feedback)46.06 kB--
@sentry/browser (incl. sendFeedback)33.64 kB--
@sentry/browser (incl. FeedbackAsync)38.74 kB--
@sentry/browser (incl. Metrics)29.52 kB--
@sentry/browser (incl. Logs)29.81 kB--
@sentry/browser (incl. Metrics & Logs)30.45 kB--
@sentry/react30.32 kB--
@sentry/react (incl. Tracing)51.08 kB--
@sentry/vue35.74 kB--
@sentry/vue (incl. Tracing)51.14 kB--
@sentry/svelte28.6 kB--
CDN Bundle30.36 kB--
CDN Bundle (incl. Tracing)49.52 kB--
CDN Bundle (incl. Logs, Metrics)32.59 kB--
CDN Bundle (incl. Tracing, Logs, Metrics)51.43 kB--
CDN Bundle (incl. Replay, Logs, Metrics)73.19 kB--
CDN Bundle (incl. Tracing, Replay)87.01 kB--
CDN Bundle (incl. Tracing, Replay, Logs, Metrics)88.88 kB--
CDN Bundle (incl. Tracing, Replay, Feedback)92.94 kB--
CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics)94.84 kB--
CDN Bundle - uncompressed89.97 kB--
CDN Bundle (incl. Tracing) - uncompressed147.58 kB--
CDN Bundle (incl. Logs, Metrics) - uncompressed96.27 kB--
CDN Bundle (incl. Tracing, Logs, Metrics) - uncompressed153.27 kB--
CDN Bundle (incl. Replay, Logs, Metrics) - uncompressed225.43 kB--
CDN Bundle (incl. Tracing, Replay) - uncompressed267.07 kB--
CDN Bundle (incl. Tracing, Replay, Logs, Metrics) - uncompressed272.75 kB--
CDN Bundle (incl. Tracing, Replay, Feedback) - uncompressed280.77 kB--
CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics) - uncompressed286.44 kB--
@sentry/nextjs (client)53.7 kB--
@sentry/sveltekit (client)49.3 kB--
@sentry/core/server40.74 kB--
@sentry/core/browser13.42 kB--
@sentry/node124.05 kB+0.02%+22 B 🔺
@sentry/node/import (ESM hook with diagnostics-channel injection)81.51 kB--
@sentry/node - without tracing88.3 kB+0.03%+21 B 🔺
@sentry/node - without channel injection103.36 kB+0.03%+22 B 🔺
@sentry/aws-serverless96.66 kB+0.03%+25 B 🔺
@sentry/cloudflare (withSentry) - minified201.23 kB--
@sentry/cloudflare (withSentry)500.94 kB--

View base workflow run

@andreiborza
andreiborza merged commit 7fd2c1b into developSep 2, 2026
256 checks passed
JPeer264 added a commit that referenced this pull request Sep 2, 2026
Ports `cloudflare-orchestrion-mysql` to span streaming.
Streamed mysql spans are named by the low-cardinality query summary,
which is `SELECT` for both statements in this app, so the spec locates
the spans by their `db.query.text` attribute and pins the `SELECT` name
separately. `collectStreamedSpans` groups spans by trace since #23912,
so the predicate only has to see the `/test-mysql` segment and the `db`
spans; the nested-query test keeps proving the async context restore by
requiring both spans in that trace.
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
JPeer264 added a commit that referenced this pull request Sep 2, 2026
Ports `cloudflare-agent` to span streaming. The gen_ai assertions were
already on streamed spans; the remaining `waitForTransaction` calls are
replaced.
- The worker and the Agent Durable Object both emit a `GET` segment for
the same URL. The DO segment is picked by `url.path` plus a defined
`parent_span_id` (the worker propagates its trace over the RPC binding),
same discriminator the old spec used.
- The three surviving storage spans are children of the `greet` rpc
span, so they are selected by `parent_span_id` and ordered by
`start_timestamp`; the count-based filter proof is unchanged.
- gen_ai-to-segment relations rely on `collectStreamedSpans` grouping by
trace (#23912): the collect finishes once the owning segment has
arrived, so no manual `trace_id` matching is needed.
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Sign up for freeto 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.

2 participants

@andreiborza@chargome
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

test(e2e): Group collectStreamedSpans by trace - #23912

Merged
andreiborza merged 1 commit into
developfrom
ab/js-3482/collect-streamed-spans
Sep 2, 2026
Merged

test(e2e): Group collectStreamedSpans by trace#23912
andreiborza merged 1 commit into
developfrom
ab/js-3482/collect-streamed-spans

Conversation

@andreiborza

@andreiborzaandreiborza commented Sep 2, 2026

Copy link
Copy Markdown
Member

What

Groups the spans collectStreamedSpans accumulates by trace, so its predicate sees one trace at a time instead of a flat pile, and it resolves with only that trace's spans. Also re-exports SerializedStreamedSpan so specs can type their span helpers.

Why

Spans are buffered per trace and flushed on a timer, so a previous test's spans can still be arriving when the next one starts collecting. A test asserting on one request's children could therefore mix in an earlier page load's spans, or have its wait satisfied by them before its own spans arrived. Every trace is evaluated as a candidate, so a leftover trace that never satisfies the predicate cannot hold up the one that does.

Note this scopes a result to a single trace, it does not identify which trace: when several tests exercise the same route, the predicate still has to name something unique to the request under test.

Split out of the React Router porting stack because it is useful on its own, and other span streaming ports can drop their hand-rolled trace_id filtering once it lands.

It accumulated every span envelope into a single array, so a test asserting on
one request's children could mix in spans from an earlier page load's trace, or
have its wait satisfied by them. Spans are bucketed per trace now and the
predicate sees one trace at a time, so it resolves with a coherent set.
Every trace is evaluated as a candidate, so a leftover trace that never satisfies
the predicate cannot hold up the one that does. Note this scopes a result to a
single trace, it does not identify which trace: when several tests exercise the
same route, the predicate still has to name something unique to the request under
test.
Also re-exports `SerializedStreamedSpan`, which specs need to type their span
helpers.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@linear-code

Copy link
Copy Markdown

JS-3482

@github-actions

Copy link
Copy Markdown
Contributor

size-limit report 📦

PathSize% ChangeChange
@sentry/browser28.57 kB--
@sentry/browser - with treeshaking flags26.94 kB--
@sentry/browser - with treeshaking flags tracing without tracing26.83 kB--
@sentry/browser (incl. Tracing)48.87 kB--
@sentry/browser (incl. Tracing + Span Streaming)48.88 kB--
@sentry/browser (incl. Tracing, Profiling)51.8 kB--
@sentry/browser (incl. Tracing, Replay)88.36 kB--
@sentry/browser (incl. Tracing, Replay) - with treeshaking flags77.76 kB--
@sentry/browser (incl. Tracing, Replay with Canvas)93.05 kB--
@sentry/browser (incl. Tracing, Replay, Feedback)106.02 kB--
@sentry/browser (incl. Feedback)46.06 kB--
@sentry/browser (incl. sendFeedback)33.64 kB--
@sentry/browser (incl. FeedbackAsync)38.74 kB--
@sentry/browser (incl. Metrics)29.52 kB--
@sentry/browser (incl. Logs)29.81 kB--
@sentry/browser (incl. Metrics & Logs)30.45 kB--
@sentry/react30.32 kB--
@sentry/react (incl. Tracing)51.08 kB--
@sentry/vue35.74 kB--
@sentry/vue (incl. Tracing)51.14 kB--
@sentry/svelte28.6 kB--
CDN Bundle30.36 kB--
CDN Bundle (incl. Tracing)49.52 kB--
CDN Bundle (incl. Logs, Metrics)32.59 kB--
CDN Bundle (incl. Tracing, Logs, Metrics)51.43 kB--
CDN Bundle (incl. Replay, Logs, Metrics)73.19 kB--
CDN Bundle (incl. Tracing, Replay)87.01 kB--
CDN Bundle (incl. Tracing, Replay, Logs, Metrics)88.88 kB--
CDN Bundle (incl. Tracing, Replay, Feedback)92.94 kB--
CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics)94.84 kB--
CDN Bundle - uncompressed89.97 kB--
CDN Bundle (incl. Tracing) - uncompressed147.58 kB--
CDN Bundle (incl. Logs, Metrics) - uncompressed96.27 kB--
CDN Bundle (incl. Tracing, Logs, Metrics) - uncompressed153.27 kB--
CDN Bundle (incl. Replay, Logs, Metrics) - uncompressed225.43 kB--
CDN Bundle (incl. Tracing, Replay) - uncompressed267.07 kB--
CDN Bundle (incl. Tracing, Replay, Logs, Metrics) - uncompressed272.75 kB--
CDN Bundle (incl. Tracing, Replay, Feedback) - uncompressed280.77 kB--
CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics) - uncompressed286.44 kB--
@sentry/nextjs (client)53.7 kB--
@sentry/sveltekit (client)49.3 kB--
@sentry/core/server40.74 kB--
@sentry/core/browser13.42 kB--
@sentry/node124.05 kB+0.02%+22 B 🔺
@sentry/node/import (ESM hook with diagnostics-channel injection)81.51 kB--
@sentry/node - without tracing88.3 kB+0.03%+21 B 🔺
@sentry/node - without channel injection103.36 kB+0.03%+22 B 🔺
@sentry/aws-serverless96.66 kB+0.03%+25 B 🔺
@sentry/cloudflare (withSentry) - minified201.23 kB--
@sentry/cloudflare (withSentry)500.94 kB--

View base workflow run

@andreiborza
andreiborza merged commit 7fd2c1b into developSep 2, 2026
256 checks passed
JPeer264 added a commit that referenced this pull request Sep 2, 2026
Ports `cloudflare-orchestrion-mysql` to span streaming.
Streamed mysql spans are named by the low-cardinality query summary,
which is `SELECT` for both statements in this app, so the spec locates
the spans by their `db.query.text` attribute and pins the `SELECT` name
separately. `collectStreamedSpans` groups spans by trace since #23912,
so the predicate only has to see the `/test-mysql` segment and the `db`
spans; the nested-query test keeps proving the async context restore by
requiring both spans in that trace.
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
JPeer264 added a commit that referenced this pull request Sep 2, 2026
Ports `cloudflare-agent` to span streaming. The gen_ai assertions were
already on streamed spans; the remaining `waitForTransaction` calls are
replaced.
- The worker and the Agent Durable Object both emit a `GET` segment for
the same URL. The DO segment is picked by `url.path` plus a defined
`parent_span_id` (the worker propagates its trace over the RPC binding),
same discriminator the old spec used.
- The three surviving storage spans are children of the `greet` rpc
span, so they are selected by `parent_span_id` and ordered by
`start_timestamp`; the count-based filter proof is unchanged.
- gen_ai-to-segment relations rely on `collectStreamedSpans` grouping by
trace (#23912): the collect finishes once the owning segment has
arrived, so no manual `trace_id` matching is needed.
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Sign up for freeto 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.

2 participants

@andreiborza@chargome
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

test(e2e): Group collectStreamedSpans by trace - #23912

Merged
andreiborza merged 1 commit into
developfrom
ab/js-3482/collect-streamed-spans
Sep 2, 2026
Merged

test(e2e): Group collectStreamedSpans by trace#23912
andreiborza merged 1 commit into
developfrom
ab/js-3482/collect-streamed-spans

Conversation

@andreiborza

@andreiborzaandreiborza commented Sep 2, 2026

Copy link
Copy Markdown
Member

What

Groups the spans collectStreamedSpans accumulates by trace, so its predicate sees one trace at a time instead of a flat pile, and it resolves with only that trace's spans. Also re-exports SerializedStreamedSpan so specs can type their span helpers.

Why

Spans are buffered per trace and flushed on a timer, so a previous test's spans can still be arriving when the next one starts collecting. A test asserting on one request's children could therefore mix in an earlier page load's spans, or have its wait satisfied by them before its own spans arrived. Every trace is evaluated as a candidate, so a leftover trace that never satisfies the predicate cannot hold up the one that does.

Note this scopes a result to a single trace, it does not identify which trace: when several tests exercise the same route, the predicate still has to name something unique to the request under test.

Split out of the React Router porting stack because it is useful on its own, and other span streaming ports can drop their hand-rolled trace_id filtering once it lands.

It accumulated every span envelope into a single array, so a test asserting on
one request's children could mix in spans from an earlier page load's trace, or
have its wait satisfied by them. Spans are bucketed per trace now and the
predicate sees one trace at a time, so it resolves with a coherent set.
Every trace is evaluated as a candidate, so a leftover trace that never satisfies
the predicate cannot hold up the one that does. Note this scopes a result to a
single trace, it does not identify which trace: when several tests exercise the
same route, the predicate still has to name something unique to the request under
test.
Also re-exports `SerializedStreamedSpan`, which specs need to type their span
helpers.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@linear-code

Copy link
Copy Markdown

JS-3482

@github-actions

Copy link
Copy Markdown
Contributor

size-limit report 📦

PathSize% ChangeChange
@sentry/browser28.57 kB--
@sentry/browser - with treeshaking flags26.94 kB--
@sentry/browser - with treeshaking flags tracing without tracing26.83 kB--
@sentry/browser (incl. Tracing)48.87 kB--
@sentry/browser (incl. Tracing + Span Streaming)48.88 kB--
@sentry/browser (incl. Tracing, Profiling)51.8 kB--
@sentry/browser (incl. Tracing, Replay)88.36 kB--
@sentry/browser (incl. Tracing, Replay) - with treeshaking flags77.76 kB--
@sentry/browser (incl. Tracing, Replay with Canvas)93.05 kB--
@sentry/browser (incl. Tracing, Replay, Feedback)106.02 kB--
@sentry/browser (incl. Feedback)46.06 kB--
@sentry/browser (incl. sendFeedback)33.64 kB--
@sentry/browser (incl. FeedbackAsync)38.74 kB--
@sentry/browser (incl. Metrics)29.52 kB--
@sentry/browser (incl. Logs)29.81 kB--
@sentry/browser (incl. Metrics & Logs)30.45 kB--
@sentry/react30.32 kB--
@sentry/react (incl. Tracing)51.08 kB--
@sentry/vue35.74 kB--
@sentry/vue (incl. Tracing)51.14 kB--
@sentry/svelte28.6 kB--
CDN Bundle30.36 kB--
CDN Bundle (incl. Tracing)49.52 kB--
CDN Bundle (incl. Logs, Metrics)32.59 kB--
CDN Bundle (incl. Tracing, Logs, Metrics)51.43 kB--
CDN Bundle (incl. Replay, Logs, Metrics)73.19 kB--
CDN Bundle (incl. Tracing, Replay)87.01 kB--
CDN Bundle (incl. Tracing, Replay, Logs, Metrics)88.88 kB--
CDN Bundle (incl. Tracing, Replay, Feedback)92.94 kB--
CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics)94.84 kB--
CDN Bundle - uncompressed89.97 kB--
CDN Bundle (incl. Tracing) - uncompressed147.58 kB--
CDN Bundle (incl. Logs, Metrics) - uncompressed96.27 kB--
CDN Bundle (incl. Tracing, Logs, Metrics) - uncompressed153.27 kB--
CDN Bundle (incl. Replay, Logs, Metrics) - uncompressed225.43 kB--
CDN Bundle (incl. Tracing, Replay) - uncompressed267.07 kB--
CDN Bundle (incl. Tracing, Replay, Logs, Metrics) - uncompressed272.75 kB--
CDN Bundle (incl. Tracing, Replay, Feedback) - uncompressed280.77 kB--
CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics) - uncompressed286.44 kB--
@sentry/nextjs (client)53.7 kB--
@sentry/sveltekit (client)49.3 kB--
@sentry/core/server40.74 kB--
@sentry/core/browser13.42 kB--
@sentry/node124.05 kB+0.02%+22 B 🔺
@sentry/node/import (ESM hook with diagnostics-channel injection)81.51 kB--
@sentry/node - without tracing88.3 kB+0.03%+21 B 🔺
@sentry/node - without channel injection103.36 kB+0.03%+22 B 🔺
@sentry/aws-serverless96.66 kB+0.03%+25 B 🔺
@sentry/cloudflare (withSentry) - minified201.23 kB--
@sentry/cloudflare (withSentry)500.94 kB--

View base workflow run

@andreiborza
andreiborza merged commit 7fd2c1b into developSep 2, 2026
256 checks passed
JPeer264 added a commit that referenced this pull request Sep 2, 2026
Ports `cloudflare-orchestrion-mysql` to span streaming.
Streamed mysql spans are named by the low-cardinality query summary,
which is `SELECT` for both statements in this app, so the spec locates
the spans by their `db.query.text` attribute and pins the `SELECT` name
separately. `collectStreamedSpans` groups spans by trace since #23912,
so the predicate only has to see the `/test-mysql` segment and the `db`
spans; the nested-query test keeps proving the async context restore by
requiring both spans in that trace.
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
JPeer264 added a commit that referenced this pull request Sep 2, 2026
Ports `cloudflare-agent` to span streaming. The gen_ai assertions were
already on streamed spans; the remaining `waitForTransaction` calls are
replaced.
- The worker and the Agent Durable Object both emit a `GET` segment for
the same URL. The DO segment is picked by `url.path` plus a defined
`parent_span_id` (the worker propagates its trace over the RPC binding),
same discriminator the old spec used.
- The three surviving storage spans are children of the `greet` rpc
span, so they are selected by `parent_span_id` and ordered by
`start_timestamp`; the count-based filter proof is unchanged.
- gen_ai-to-segment relations rely on `collectStreamedSpans` grouping by
trace (#23912): the collect finishes once the owning segment has
arrived, so no manual `trace_id` matching is needed.
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Sign up for freeto 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.

2 participants

@andreiborza@chargome
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

test(e2e): Group collectStreamedSpans by trace - #23912

Merged
andreiborza merged 1 commit into
developfrom
ab/js-3482/collect-streamed-spans
Sep 2, 2026
Merged

test(e2e): Group collectStreamedSpans by trace#23912
andreiborza merged 1 commit into
developfrom
ab/js-3482/collect-streamed-spans

Conversation

@andreiborza

@andreiborzaandreiborza commented Sep 2, 2026

Copy link
Copy Markdown
Member

What

Groups the spans collectStreamedSpans accumulates by trace, so its predicate sees one trace at a time instead of a flat pile, and it resolves with only that trace's spans. Also re-exports SerializedStreamedSpan so specs can type their span helpers.

Why

Spans are buffered per trace and flushed on a timer, so a previous test's spans can still be arriving when the next one starts collecting. A test asserting on one request's children could therefore mix in an earlier page load's spans, or have its wait satisfied by them before its own spans arrived. Every trace is evaluated as a candidate, so a leftover trace that never satisfies the predicate cannot hold up the one that does.

Note this scopes a result to a single trace, it does not identify which trace: when several tests exercise the same route, the predicate still has to name something unique to the request under test.

Split out of the React Router porting stack because it is useful on its own, and other span streaming ports can drop their hand-rolled trace_id filtering once it lands.

It accumulated every span envelope into a single array, so a test asserting on
one request's children could mix in spans from an earlier page load's trace, or
have its wait satisfied by them. Spans are bucketed per trace now and the
predicate sees one trace at a time, so it resolves with a coherent set.
Every trace is evaluated as a candidate, so a leftover trace that never satisfies
the predicate cannot hold up the one that does. Note this scopes a result to a
single trace, it does not identify which trace: when several tests exercise the
same route, the predicate still has to name something unique to the request under
test.
Also re-exports `SerializedStreamedSpan`, which specs need to type their span
helpers.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@linear-code

Copy link
Copy Markdown

JS-3482

@github-actions

Copy link
Copy Markdown
Contributor

size-limit report 📦

PathSize% ChangeChange
@sentry/browser28.57 kB--
@sentry/browser - with treeshaking flags26.94 kB--
@sentry/browser - with treeshaking flags tracing without tracing26.83 kB--
@sentry/browser (incl. Tracing)48.87 kB--
@sentry/browser (incl. Tracing + Span Streaming)48.88 kB--
@sentry/browser (incl. Tracing, Profiling)51.8 kB--
@sentry/browser (incl. Tracing, Replay)88.36 kB--
@sentry/browser (incl. Tracing, Replay) - with treeshaking flags77.76 kB--
@sentry/browser (incl. Tracing, Replay with Canvas)93.05 kB--
@sentry/browser (incl. Tracing, Replay, Feedback)106.02 kB--
@sentry/browser (incl. Feedback)46.06 kB--
@sentry/browser (incl. sendFeedback)33.64 kB--
@sentry/browser (incl. FeedbackAsync)38.74 kB--
@sentry/browser (incl. Metrics)29.52 kB--
@sentry/browser (incl. Logs)29.81 kB--
@sentry/browser (incl. Metrics & Logs)30.45 kB--
@sentry/react30.32 kB--
@sentry/react (incl. Tracing)51.08 kB--
@sentry/vue35.74 kB--
@sentry/vue (incl. Tracing)51.14 kB--
@sentry/svelte28.6 kB--
CDN Bundle30.36 kB--
CDN Bundle (incl. Tracing)49.52 kB--
CDN Bundle (incl. Logs, Metrics)32.59 kB--
CDN Bundle (incl. Tracing, Logs, Metrics)51.43 kB--
CDN Bundle (incl. Replay, Logs, Metrics)73.19 kB--
CDN Bundle (incl. Tracing, Replay)87.01 kB--
CDN Bundle (incl. Tracing, Replay, Logs, Metrics)88.88 kB--
CDN Bundle (incl. Tracing, Replay, Feedback)92.94 kB--
CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics)94.84 kB--
CDN Bundle - uncompressed89.97 kB--
CDN Bundle (incl. Tracing) - uncompressed147.58 kB--
CDN Bundle (incl. Logs, Metrics) - uncompressed96.27 kB--
CDN Bundle (incl. Tracing, Logs, Metrics) - uncompressed153.27 kB--
CDN Bundle (incl. Replay, Logs, Metrics) - uncompressed225.43 kB--
CDN Bundle (incl. Tracing, Replay) - uncompressed267.07 kB--
CDN Bundle (incl. Tracing, Replay, Logs, Metrics) - uncompressed272.75 kB--
CDN Bundle (incl. Tracing, Replay, Feedback) - uncompressed280.77 kB--
CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics) - uncompressed286.44 kB--
@sentry/nextjs (client)53.7 kB--
@sentry/sveltekit (client)49.3 kB--
@sentry/core/server40.74 kB--
@sentry/core/browser13.42 kB--
@sentry/node124.05 kB+0.02%+22 B 🔺
@sentry/node/import (ESM hook with diagnostics-channel injection)81.51 kB--
@sentry/node - without tracing88.3 kB+0.03%+21 B 🔺
@sentry/node - without channel injection103.36 kB+0.03%+22 B 🔺
@sentry/aws-serverless96.66 kB+0.03%+25 B 🔺
@sentry/cloudflare (withSentry) - minified201.23 kB--
@sentry/cloudflare (withSentry)500.94 kB--

View base workflow run

@andreiborza
andreiborza merged commit 7fd2c1b into developSep 2, 2026
256 checks passed
JPeer264 added a commit that referenced this pull request Sep 2, 2026
Ports `cloudflare-orchestrion-mysql` to span streaming.
Streamed mysql spans are named by the low-cardinality query summary,
which is `SELECT` for both statements in this app, so the spec locates
the spans by their `db.query.text` attribute and pins the `SELECT` name
separately. `collectStreamedSpans` groups spans by trace since #23912,
so the predicate only has to see the `/test-mysql` segment and the `db`
spans; the nested-query test keeps proving the async context restore by
requiring both spans in that trace.
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
JPeer264 added a commit that referenced this pull request Sep 2, 2026
Ports `cloudflare-agent` to span streaming. The gen_ai assertions were
already on streamed spans; the remaining `waitForTransaction` calls are
replaced.
- The worker and the Agent Durable Object both emit a `GET` segment for
the same URL. The DO segment is picked by `url.path` plus a defined
`parent_span_id` (the worker propagates its trace over the RPC binding),
same discriminator the old spec used.
- The three surviving storage spans are children of the `greet` rpc
span, so they are selected by `parent_span_id` and ordered by
`start_timestamp`; the count-based filter proof is unchanged.
- gen_ai-to-segment relations rely on `collectStreamedSpans` grouping by
trace (#23912): the collect finishes once the owning segment has
arrived, so no manual `trace_id` matching is needed.
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Sign up for freeto 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.

2 participants

@andreiborza@chargome
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

test(e2e): Group collectStreamedSpans by trace - #23912

Merged
andreiborza merged 1 commit into
developfrom
ab/js-3482/collect-streamed-spans
Sep 2, 2026
Merged

test(e2e): Group collectStreamedSpans by trace#23912
andreiborza merged 1 commit into
developfrom
ab/js-3482/collect-streamed-spans

Conversation

@andreiborza

@andreiborzaandreiborza commented Sep 2, 2026

Copy link
Copy Markdown
Member

What

Groups the spans collectStreamedSpans accumulates by trace, so its predicate sees one trace at a time instead of a flat pile, and it resolves with only that trace's spans. Also re-exports SerializedStreamedSpan so specs can type their span helpers.

Why

Spans are buffered per trace and flushed on a timer, so a previous test's spans can still be arriving when the next one starts collecting. A test asserting on one request's children could therefore mix in an earlier page load's spans, or have its wait satisfied by them before its own spans arrived. Every trace is evaluated as a candidate, so a leftover trace that never satisfies the predicate cannot hold up the one that does.

Note this scopes a result to a single trace, it does not identify which trace: when several tests exercise the same route, the predicate still has to name something unique to the request under test.

Split out of the React Router porting stack because it is useful on its own, and other span streaming ports can drop their hand-rolled trace_id filtering once it lands.

It accumulated every span envelope into a single array, so a test asserting on
one request's children could mix in spans from an earlier page load's trace, or
have its wait satisfied by them. Spans are bucketed per trace now and the
predicate sees one trace at a time, so it resolves with a coherent set.
Every trace is evaluated as a candidate, so a leftover trace that never satisfies
the predicate cannot hold up the one that does. Note this scopes a result to a
single trace, it does not identify which trace: when several tests exercise the
same route, the predicate still has to name something unique to the request under
test.
Also re-exports `SerializedStreamedSpan`, which specs need to type their span
helpers.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@linear-code

Copy link
Copy Markdown

JS-3482

@github-actions

Copy link
Copy Markdown
Contributor

size-limit report 📦

PathSize% ChangeChange
@sentry/browser28.57 kB--
@sentry/browser - with treeshaking flags26.94 kB--
@sentry/browser - with treeshaking flags tracing without tracing26.83 kB--
@sentry/browser (incl. Tracing)48.87 kB--
@sentry/browser (incl. Tracing + Span Streaming)48.88 kB--
@sentry/browser (incl. Tracing, Profiling)51.8 kB--
@sentry/browser (incl. Tracing, Replay)88.36 kB--
@sentry/browser (incl. Tracing, Replay) - with treeshaking flags77.76 kB--
@sentry/browser (incl. Tracing, Replay with Canvas)93.05 kB--
@sentry/browser (incl. Tracing, Replay, Feedback)106.02 kB--
@sentry/browser (incl. Feedback)46.06 kB--
@sentry/browser (incl. sendFeedback)33.64 kB--
@sentry/browser (incl. FeedbackAsync)38.74 kB--
@sentry/browser (incl. Metrics)29.52 kB--
@sentry/browser (incl. Logs)29.81 kB--
@sentry/browser (incl. Metrics & Logs)30.45 kB--
@sentry/react30.32 kB--
@sentry/react (incl. Tracing)51.08 kB--
@sentry/vue35.74 kB--
@sentry/vue (incl. Tracing)51.14 kB--
@sentry/svelte28.6 kB--
CDN Bundle30.36 kB--
CDN Bundle (incl. Tracing)49.52 kB--
CDN Bundle (incl. Logs, Metrics)32.59 kB--
CDN Bundle (incl. Tracing, Logs, Metrics)51.43 kB--
CDN Bundle (incl. Replay, Logs, Metrics)73.19 kB--
CDN Bundle (incl. Tracing, Replay)87.01 kB--
CDN Bundle (incl. Tracing, Replay, Logs, Metrics)88.88 kB--
CDN Bundle (incl. Tracing, Replay, Feedback)92.94 kB--
CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics)94.84 kB--
CDN Bundle - uncompressed89.97 kB--
CDN Bundle (incl. Tracing) - uncompressed147.58 kB--
CDN Bundle (incl. Logs, Metrics) - uncompressed96.27 kB--
CDN Bundle (incl. Tracing, Logs, Metrics) - uncompressed153.27 kB--
CDN Bundle (incl. Replay, Logs, Metrics) - uncompressed225.43 kB--
CDN Bundle (incl. Tracing, Replay) - uncompressed267.07 kB--
CDN Bundle (incl. Tracing, Replay, Logs, Metrics) - uncompressed272.75 kB--
CDN Bundle (incl. Tracing, Replay, Feedback) - uncompressed280.77 kB--
CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics) - uncompressed286.44 kB--
@sentry/nextjs (client)53.7 kB--
@sentry/sveltekit (client)49.3 kB--
@sentry/core/server40.74 kB--
@sentry/core/browser13.42 kB--
@sentry/node124.05 kB+0.02%+22 B 🔺
@sentry/node/import (ESM hook with diagnostics-channel injection)81.51 kB--
@sentry/node - without tracing88.3 kB+0.03%+21 B 🔺
@sentry/node - without channel injection103.36 kB+0.03%+22 B 🔺
@sentry/aws-serverless96.66 kB+0.03%+25 B 🔺
@sentry/cloudflare (withSentry) - minified201.23 kB--
@sentry/cloudflare (withSentry)500.94 kB--

View base workflow run

@andreiborza
andreiborza merged commit 7fd2c1b into developSep 2, 2026
256 checks passed
JPeer264 added a commit that referenced this pull request Sep 2, 2026
Ports `cloudflare-orchestrion-mysql` to span streaming.
Streamed mysql spans are named by the low-cardinality query summary,
which is `SELECT` for both statements in this app, so the spec locates
the spans by their `db.query.text` attribute and pins the `SELECT` name
separately. `collectStreamedSpans` groups spans by trace since #23912,
so the predicate only has to see the `/test-mysql` segment and the `db`
spans; the nested-query test keeps proving the async context restore by
requiring both spans in that trace.
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
JPeer264 added a commit that referenced this pull request Sep 2, 2026
Ports `cloudflare-agent` to span streaming. The gen_ai assertions were
already on streamed spans; the remaining `waitForTransaction` calls are
replaced.
- The worker and the Agent Durable Object both emit a `GET` segment for
the same URL. The DO segment is picked by `url.path` plus a defined
`parent_span_id` (the worker propagates its trace over the RPC binding),
same discriminator the old spec used.
- The three surviving storage spans are children of the `greet` rpc
span, so they are selected by `parent_span_id` and ordered by
`start_timestamp`; the count-based filter proof is unchanged.
- gen_ai-to-segment relations rely on `collectStreamedSpans` grouping by
trace (#23912): the collect finishes once the owning segment has
arrived, so no manual `trace_id` matching is needed.
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Sign up for freeto 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.

2 participants

@andreiborza@chargome
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

test(e2e): Group collectStreamedSpans by trace - #23912

Merged
andreiborza merged 1 commit into
developfrom
ab/js-3482/collect-streamed-spans
Sep 2, 2026
Merged

test(e2e): Group collectStreamedSpans by trace#23912
andreiborza merged 1 commit into
developfrom
ab/js-3482/collect-streamed-spans

Conversation

@andreiborza

@andreiborzaandreiborza commented Sep 2, 2026

Copy link
Copy Markdown
Member

What

Groups the spans collectStreamedSpans accumulates by trace, so its predicate sees one trace at a time instead of a flat pile, and it resolves with only that trace's spans. Also re-exports SerializedStreamedSpan so specs can type their span helpers.

Why

Spans are buffered per trace and flushed on a timer, so a previous test's spans can still be arriving when the next one starts collecting. A test asserting on one request's children could therefore mix in an earlier page load's spans, or have its wait satisfied by them before its own spans arrived. Every trace is evaluated as a candidate, so a leftover trace that never satisfies the predicate cannot hold up the one that does.

Note this scopes a result to a single trace, it does not identify which trace: when several tests exercise the same route, the predicate still has to name something unique to the request under test.

Split out of the React Router porting stack because it is useful on its own, and other span streaming ports can drop their hand-rolled trace_id filtering once it lands.

It accumulated every span envelope into a single array, so a test asserting on
one request's children could mix in spans from an earlier page load's trace, or
have its wait satisfied by them. Spans are bucketed per trace now and the
predicate sees one trace at a time, so it resolves with a coherent set.
Every trace is evaluated as a candidate, so a leftover trace that never satisfies
the predicate cannot hold up the one that does. Note this scopes a result to a
single trace, it does not identify which trace: when several tests exercise the
same route, the predicate still has to name something unique to the request under
test.
Also re-exports `SerializedStreamedSpan`, which specs need to type their span
helpers.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@linear-code

Copy link
Copy Markdown

JS-3482

@github-actions

Copy link
Copy Markdown
Contributor

size-limit report 📦

PathSize% ChangeChange
@sentry/browser28.57 kB--
@sentry/browser - with treeshaking flags26.94 kB--
@sentry/browser - with treeshaking flags tracing without tracing26.83 kB--
@sentry/browser (incl. Tracing)48.87 kB--
@sentry/browser (incl. Tracing + Span Streaming)48.88 kB--
@sentry/browser (incl. Tracing, Profiling)51.8 kB--
@sentry/browser (incl. Tracing, Replay)88.36 kB--
@sentry/browser (incl. Tracing, Replay) - with treeshaking flags77.76 kB--
@sentry/browser (incl. Tracing, Replay with Canvas)93.05 kB--
@sentry/browser (incl. Tracing, Replay, Feedback)106.02 kB--
@sentry/browser (incl. Feedback)46.06 kB--
@sentry/browser (incl. sendFeedback)33.64 kB--
@sentry/browser (incl. FeedbackAsync)38.74 kB--
@sentry/browser (incl. Metrics)29.52 kB--
@sentry/browser (incl. Logs)29.81 kB--
@sentry/browser (incl. Metrics & Logs)30.45 kB--
@sentry/react30.32 kB--
@sentry/react (incl. Tracing)51.08 kB--
@sentry/vue35.74 kB--
@sentry/vue (incl. Tracing)51.14 kB--
@sentry/svelte28.6 kB--
CDN Bundle30.36 kB--
CDN Bundle (incl. Tracing)49.52 kB--
CDN Bundle (incl. Logs, Metrics)32.59 kB--
CDN Bundle (incl. Tracing, Logs, Metrics)51.43 kB--
CDN Bundle (incl. Replay, Logs, Metrics)73.19 kB--
CDN Bundle (incl. Tracing, Replay)87.01 kB--
CDN Bundle (incl. Tracing, Replay, Logs, Metrics)88.88 kB--
CDN Bundle (incl. Tracing, Replay, Feedback)92.94 kB--
CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics)94.84 kB--
CDN Bundle - uncompressed89.97 kB--
CDN Bundle (incl. Tracing) - uncompressed147.58 kB--
CDN Bundle (incl. Logs, Metrics) - uncompressed96.27 kB--
CDN Bundle (incl. Tracing, Logs, Metrics) - uncompressed153.27 kB--
CDN Bundle (incl. Replay, Logs, Metrics) - uncompressed225.43 kB--
CDN Bundle (incl. Tracing, Replay) - uncompressed267.07 kB--
CDN Bundle (incl. Tracing, Replay, Logs, Metrics) - uncompressed272.75 kB--
CDN Bundle (incl. Tracing, Replay, Feedback) - uncompressed280.77 kB--
CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics) - uncompressed286.44 kB--
@sentry/nextjs (client)53.7 kB--
@sentry/sveltekit (client)49.3 kB--
@sentry/core/server40.74 kB--
@sentry/core/browser13.42 kB--
@sentry/node124.05 kB+0.02%+22 B 🔺
@sentry/node/import (ESM hook with diagnostics-channel injection)81.51 kB--
@sentry/node - without tracing88.3 kB+0.03%+21 B 🔺
@sentry/node - without channel injection103.36 kB+0.03%+22 B 🔺
@sentry/aws-serverless96.66 kB+0.03%+25 B 🔺
@sentry/cloudflare (withSentry) - minified201.23 kB--
@sentry/cloudflare (withSentry)500.94 kB--

View base workflow run

@andreiborza
andreiborza merged commit 7fd2c1b into developSep 2, 2026
256 checks passed
JPeer264 added a commit that referenced this pull request Sep 2, 2026
Ports `cloudflare-orchestrion-mysql` to span streaming.
Streamed mysql spans are named by the low-cardinality query summary,
which is `SELECT` for both statements in this app, so the spec locates
the spans by their `db.query.text` attribute and pins the `SELECT` name
separately. `collectStreamedSpans` groups spans by trace since #23912,
so the predicate only has to see the `/test-mysql` segment and the `db`
spans; the nested-query test keeps proving the async context restore by
requiring both spans in that trace.
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
JPeer264 added a commit that referenced this pull request Sep 2, 2026
Ports `cloudflare-agent` to span streaming. The gen_ai assertions were
already on streamed spans; the remaining `waitForTransaction` calls are
replaced.
- The worker and the Agent Durable Object both emit a `GET` segment for
the same URL. The DO segment is picked by `url.path` plus a defined
`parent_span_id` (the worker propagates its trace over the RPC binding),
same discriminator the old spec used.
- The three surviving storage spans are children of the `greet` rpc
span, so they are selected by `parent_span_id` and ordered by
`start_timestamp`; the count-based filter proof is unchanged.
- gen_ai-to-segment relations rely on `collectStreamedSpans` grouping by
trace (#23912): the collect finishes once the owning segment has
arrived, so no manual `trace_id` matching is needed.
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Sign up for freeto 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.

2 participants

@andreiborza@chargome
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

test(e2e): Group collectStreamedSpans by trace - #23912

Merged
andreiborza merged 1 commit into
developfrom
ab/js-3482/collect-streamed-spans
Sep 2, 2026
Merged

test(e2e): Group collectStreamedSpans by trace#23912
andreiborza merged 1 commit into
developfrom
ab/js-3482/collect-streamed-spans

Conversation

@andreiborza

@andreiborzaandreiborza commented Sep 2, 2026

Copy link
Copy Markdown
Member

What

Groups the spans collectStreamedSpans accumulates by trace, so its predicate sees one trace at a time instead of a flat pile, and it resolves with only that trace's spans. Also re-exports SerializedStreamedSpan so specs can type their span helpers.

Why

Spans are buffered per trace and flushed on a timer, so a previous test's spans can still be arriving when the next one starts collecting. A test asserting on one request's children could therefore mix in an earlier page load's spans, or have its wait satisfied by them before its own spans arrived. Every trace is evaluated as a candidate, so a leftover trace that never satisfies the predicate cannot hold up the one that does.

Note this scopes a result to a single trace, it does not identify which trace: when several tests exercise the same route, the predicate still has to name something unique to the request under test.

Split out of the React Router porting stack because it is useful on its own, and other span streaming ports can drop their hand-rolled trace_id filtering once it lands.

It accumulated every span envelope into a single array, so a test asserting on
one request's children could mix in spans from an earlier page load's trace, or
have its wait satisfied by them. Spans are bucketed per trace now and the
predicate sees one trace at a time, so it resolves with a coherent set.
Every trace is evaluated as a candidate, so a leftover trace that never satisfies
the predicate cannot hold up the one that does. Note this scopes a result to a
single trace, it does not identify which trace: when several tests exercise the
same route, the predicate still has to name something unique to the request under
test.
Also re-exports `SerializedStreamedSpan`, which specs need to type their span
helpers.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@linear-code

Copy link
Copy Markdown

JS-3482

@github-actions

Copy link
Copy Markdown
Contributor

size-limit report 📦

PathSize% ChangeChange
@sentry/browser28.57 kB--
@sentry/browser - with treeshaking flags26.94 kB--
@sentry/browser - with treeshaking flags tracing without tracing26.83 kB--
@sentry/browser (incl. Tracing)48.87 kB--
@sentry/browser (incl. Tracing + Span Streaming)48.88 kB--
@sentry/browser (incl. Tracing, Profiling)51.8 kB--
@sentry/browser (incl. Tracing, Replay)88.36 kB--
@sentry/browser (incl. Tracing, Replay) - with treeshaking flags77.76 kB--
@sentry/browser (incl. Tracing, Replay with Canvas)93.05 kB--
@sentry/browser (incl. Tracing, Replay, Feedback)106.02 kB--
@sentry/browser (incl. Feedback)46.06 kB--
@sentry/browser (incl. sendFeedback)33.64 kB--
@sentry/browser (incl. FeedbackAsync)38.74 kB--
@sentry/browser (incl. Metrics)29.52 kB--
@sentry/browser (incl. Logs)29.81 kB--
@sentry/browser (incl. Metrics & Logs)30.45 kB--
@sentry/react30.32 kB--
@sentry/react (incl. Tracing)51.08 kB--
@sentry/vue35.74 kB--
@sentry/vue (incl. Tracing)51.14 kB--
@sentry/svelte28.6 kB--
CDN Bundle30.36 kB--
CDN Bundle (incl. Tracing)49.52 kB--
CDN Bundle (incl. Logs, Metrics)32.59 kB--
CDN Bundle (incl. Tracing, Logs, Metrics)51.43 kB--
CDN Bundle (incl. Replay, Logs, Metrics)73.19 kB--
CDN Bundle (incl. Tracing, Replay)87.01 kB--
CDN Bundle (incl. Tracing, Replay, Logs, Metrics)88.88 kB--
CDN Bundle (incl. Tracing, Replay, Feedback)92.94 kB--
CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics)94.84 kB--
CDN Bundle - uncompressed89.97 kB--
CDN Bundle (incl. Tracing) - uncompressed147.58 kB--
CDN Bundle (incl. Logs, Metrics) - uncompressed96.27 kB--
CDN Bundle (incl. Tracing, Logs, Metrics) - uncompressed153.27 kB--
CDN Bundle (incl. Replay, Logs, Metrics) - uncompressed225.43 kB--
CDN Bundle (incl. Tracing, Replay) - uncompressed267.07 kB--
CDN Bundle (incl. Tracing, Replay, Logs, Metrics) - uncompressed272.75 kB--
CDN Bundle (incl. Tracing, Replay, Feedback) - uncompressed280.77 kB--
CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics) - uncompressed286.44 kB--
@sentry/nextjs (client)53.7 kB--
@sentry/sveltekit (client)49.3 kB--
@sentry/core/server40.74 kB--
@sentry/core/browser13.42 kB--
@sentry/node124.05 kB+0.02%+22 B 🔺
@sentry/node/import (ESM hook with diagnostics-channel injection)81.51 kB--
@sentry/node - without tracing88.3 kB+0.03%+21 B 🔺
@sentry/node - without channel injection103.36 kB+0.03%+22 B 🔺
@sentry/aws-serverless96.66 kB+0.03%+25 B 🔺
@sentry/cloudflare (withSentry) - minified201.23 kB--
@sentry/cloudflare (withSentry)500.94 kB--

View base workflow run

@andreiborza
andreiborza merged commit 7fd2c1b into developSep 2, 2026
256 checks passed
JPeer264 added a commit that referenced this pull request Sep 2, 2026
Ports `cloudflare-orchestrion-mysql` to span streaming.
Streamed mysql spans are named by the low-cardinality query summary,
which is `SELECT` for both statements in this app, so the spec locates
the spans by their `db.query.text` attribute and pins the `SELECT` name
separately. `collectStreamedSpans` groups spans by trace since #23912,
so the predicate only has to see the `/test-mysql` segment and the `db`
spans; the nested-query test keeps proving the async context restore by
requiring both spans in that trace.
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
JPeer264 added a commit that referenced this pull request Sep 2, 2026
Ports `cloudflare-agent` to span streaming. The gen_ai assertions were
already on streamed spans; the remaining `waitForTransaction` calls are
replaced.
- The worker and the Agent Durable Object both emit a `GET` segment for
the same URL. The DO segment is picked by `url.path` plus a defined
`parent_span_id` (the worker propagates its trace over the RPC binding),
same discriminator the old spec used.
- The three surviving storage spans are children of the `greet` rpc
span, so they are selected by `parent_span_id` and ordered by
`start_timestamp`; the count-based filter proof is unchanged.
- gen_ai-to-segment relations rely on `collectStreamedSpans` grouping by
trace (#23912): the collect finishes once the owning segment has
arrived, so no manual `trace_id` matching is needed.
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Sign up for freeto 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.

2 participants

@andreiborza@chargome