Porting the Next.js E2E suites to span streaming (#23802) dropped every isolation-scope assertion that was made against trace data, because span v2 has no equivalent for it. We should decide how to test scope isolation on spans and restore the coverage.
Why the coverage was lost
The suites asserted isolation scope by setting a tag in a request handler and checking it on the transaction:
expect(transaction.tags?.['my-isolated-tag']).toBe(true);
expect(transaction.tags?.['my-global-scope-isolated-tag']).not.toBeDefined();
Nothing maps scope tags (or extra) onto a streamed span. applyScopeToSegmentSpan in packages/core/src/tracing/spans/captureSpan.ts only calls scopeContextsToSpanAttributes, which converts contexts (react.version, culture.locale, response status, cloud resource, profile ids). The processSegmentSpan hooks in packages/browser and packages/aws-serverless likewise map contexts only. So there is no field on SerializedStreamedSpan where a scope tag could land.
Current state after the port
| App |
Isolation coverage now |
nextjs-app-dir |
error-side only (3 specs) |
nextjs-pages-dir |
error-side only (3 specs) |
nextjs-14 |
error-side only (1 spec) |
nextjs-16 |
none |
nextjs-16-bun |
none |
nextjs-16-cf-workers |
none |
Where an error event was involved, the error-side assertions still cover isolation and were kept. The three apps with no coverage are the ones whose isolation specs had no error to assert on.
The most valuable single loss is in nextjs-16's middleware spec, which guarded against a tag set in middleware leaking onto the following route's event — the contamination described in vercel/next.js#95306. That guard asserted the absence of a tag, so it has no error-side substitute at all.
nextjs-16-static keeps the transaction-based versions of these specs, so the behaviour is still covered under traceLifecycle: 'static' — but not under streaming, which is the default.
What to decide
Roughly, one of:
- Surface scope data on segment spans (e.g. tags as attributes) and assert on that.
- Document that scope tags are intentionally not carried on spans, and rebuild the E2E guards around a signal that does survive — attributes set explicitly by the test app, or an error event deliberately raised so the isolation assertion has a carrier.
- Accept trace-side isolation as untested under streaming and rely on unit coverage, recording that decision.
Option 2 is the cheapest to implement in the E2E suites and would restore the leak guard, which is the part worth having.
References
Porting the Next.js E2E suites to span streaming (#23802) dropped every isolation-scope assertion that was made against trace data, because span v2 has no equivalent for it. We should decide how to test scope isolation on spans and restore the coverage.
Why the coverage was lost
The suites asserted isolation scope by setting a tag in a request handler and checking it on the transaction:
Nothing maps scope
tags(orextra) onto a streamed span.applyScopeToSegmentSpaninpackages/core/src/tracing/spans/captureSpan.tsonly callsscopeContextsToSpanAttributes, which converts contexts (react.version,culture.locale, response status, cloud resource, profile ids). TheprocessSegmentSpanhooks inpackages/browserandpackages/aws-serverlesslikewise map contexts only. So there is no field onSerializedStreamedSpanwhere a scope tag could land.Current state after the port
nextjs-app-dirnextjs-pages-dirnextjs-14nextjs-16nextjs-16-bunnextjs-16-cf-workersWhere an error event was involved, the error-side assertions still cover isolation and were kept. The three apps with no coverage are the ones whose isolation specs had no error to assert on.
The most valuable single loss is in
nextjs-16's middleware spec, which guarded against a tag set in middleware leaking onto the following route's event — the contamination described in vercel/next.js#95306. That guard asserted the absence of a tag, so it has no error-side substitute at all.nextjs-16-statickeeps the transaction-based versions of these specs, so the behaviour is still covered undertraceLifecycle: 'static'— but not under streaming, which is the default.What to decide
Roughly, one of:
Option 2 is the cheapest to implement in the E2E suites and would restore the leak guard, which is the part worth having.
References
nextjs-16/tests/middleware.test.ts