Pro: restore renderer OpenTelemetry trace propagation - #4869
Conversation
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (7)
🚧 Files skipped from review as they are similar to previous changes (7)
WalkthroughReact on Rails Pro adds optional OpenTelemetry client spans for Rails-to-Node Renderer requests. It propagates W3C trace context across synchronous, asynchronous, streaming, raw-render, incremental async-props, and asset-upload flows while recording limited HTTP metadata. ChangesRenderer tracing
Estimated code review effort: 4 (Complex) | ~45 minutes Merge Risk: ⚪ Minimal · up to This change restores optional trace propagation across renderer request paths without introducing a supported merge-blocking concern; it is merge-ready after normal checks and review. Sequence Diagram(s)sequenceDiagram
participant RailsRendering
participant RendererHttpClient
participant ClientSpan
participant NodeRenderer
RailsRendering->>RendererHttpClient: Execute renderer request
RendererHttpClient->>ClientSpan: Start CLIENT span
ClientSpan->>RendererHttpClient: Inject W3C trace headers
RendererHttpClient->>NodeRenderer: Send request and trace context
NodeRenderer-->>RendererHttpClient: Return status and response chunks
RendererHttpClient->>ClientSpan: Record status and byte sizes
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches 💡 1📝 Generate docstrings 💡
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
| fiber.instance_variable_set(:@fake_open_telemetry_context, context) | ||
| block.call | ||
| ensure | ||
| fiber.instance_variable_set(:@fake_open_telemetry_context, previous) |
There was a problem hiding this comment.
Not changed. fiber is assigned before the ensure callback is registered, and that callback cannot run before the assignment completes. The focused and full Pro suites exercise this path successfully.
Greptile SummaryRestores Rails-side OpenTelemetry CLIENT spans and W3C trace propagation across regular, streaming, incremental, raw-render, and asset-upload renderer requests.
Confidence Score: 4/5The bidirectional failure path should be fixed before merging because an initial payload-write error can leave the newly created renderer span unfinished. Incremental requests mark their CLIENT span as awaiting request closure before returning the writable body, but an initial write can fail before the later async-task ensure closes that output, preventing the span from reaching its finish condition. Files Needing Attention: react_on_rails_pro/lib/react_on_rails_pro/renderer_http_client.rb Important Files Changed
Sequence DiagramsequenceDiagram
participant Rails as Rails request
participant Fiber as Async/Sync fiber
participant Client as RendererHttpClient
participant Span as OTel CLIENT span
participant Node as Node Renderer
Rails->>Fiber: Capture and restore parent context
Fiber->>Client: Renderer request
Client->>Span: Start CLIENT span
Span->>Client: Inject traceparent/tracestate
Client->>Node: HTTP request
Node-->>Client: Status and response chunks
Client->>Span: Record status and byte sizes
Client->>Span: Finish after response and request closure
Reviews (1): Last reviewed commit: "Pro: load telemetry status constants dir..." | Re-trigger Greptile |
|
|
||
| def trace=(trace) | ||
| @trace = trace | ||
| trace.wait_for_request_close |
There was a problem hiding this comment.
Bidirectional span remains unfinished
When an incremental-render request fails while writing its initial NDJSON payload, the trace has already been marked as awaiting request closure but the async task that closes the output has not yet been created, so the CLIENT span remains unsealed and is never finished or exported.
Knowledge Base Used: Pro Server Rendering Pool: Dispatching Renders to the Node-Renderer
There was a problem hiding this comment.
Not changed. post_bidi returns a lazy response and the CLIENT span starts only when that response is consumed. The initial NDJSON write happens before response enumeration, so a failure at that point cannot leave a started span unfinished. The bidirectional lifecycle specs cover closure after the span has started.
There was a problem hiding this comment.
You're right. Tracing build_response(stream: true) through Response.new(&executor) confirms the executor — and therefore start_client_trace — runs lazily inside consume, which is triggered by Response#each or Response#body. Since post_bidi skips the eager response.body call (the unless stream guard in build_response), the CLIENT span is not started until the caller iterates the response. Any failure that occurs during the pre-enumeration NDJSON write phase has no span to leave open. My original comment was incorrect. Thanks for the clarification.
Tip: You can customize Greptile's behavior for this repo with .greptile/rules.md and .greptile/config.json.
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (3)
react_on_rails_pro/spec/react_on_rails_pro/open_telemetry_spec.rb (1)
66-76: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winAvoid permanent singleton patches on a real
OpenTelemetrymodule.Line 70 skips
install_open_telemetry_constantswhenOpenTelemetry::Contextis already defined. In that case lines 73-74 redefinetracer_providerandpropagationon the real::OpenTelemetrymodule, and nothing restores them. Any later spec in the same process then sees the fake provider. The same pattern appears at lines 205, 217, and 525-526.Use
allow(OpenTelemetry).to receive(...)so RSpec reverts the stubs after each example.♻️ Proposed change
allow(provider).to receive(:tracer).with("react_on_rails_pro").and_return(tracer) - OpenTelemetry.define_singleton_method(:tracer_provider) { provider } - OpenTelemetry.define_singleton_method(:propagation) { propagator } + allow(OpenTelemetry).to receive(:tracer_provider).and_return(provider) + allow(OpenTelemetry).to receive(:propagation).and_return(propagator) span🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@react_on_rails_pro/spec/react_on_rails_pro/open_telemetry_spec.rb` around lines 66 - 76, Update install_open_telemetry and the matching setup blocks around the other reported locations to stub OpenTelemetry.tracer_provider and OpenTelemetry.propagation with RSpec allow(...).to receive(...), rather than defining singleton methods directly. Preserve the existing fake provider and propagator return values while ensuring RSpec restores the real OpenTelemetry behavior after each example.react_on_rails_pro/lib/react_on_rails_pro/renderer_http_client.rb (1)
201-231: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick winSeal the trace when
WritableBody#closeruns.
protocol-http0.62.2 does not routeWritable#closethroughclose_write. An abort such asOutput#close(error)therefore skips@trace&.seal_request_size, soClientSpancannot finish. Overridecloseand seal the request inensure, then add a regression test for the abort path.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@react_on_rails_pro/lib/react_on_rails_pro/renderer_http_client.rb` around lines 201 - 231, The WritableBody lifecycle currently seals the trace only in close_write, so aborts through WritableBody#close leave ClientSpan unfinished. Override WritableBody#close to invoke the parent close and ensure `@trace`&.seal_request_size runs, then add a regression test covering Output#close(error) and confirming the trace is sealed.react_on_rails_pro/lib/react_on_rails_pro/open_telemetry.rb (1)
194-201: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueAvoid the private
@delegateinstance variable
::OpenTelemetry::Internal::ProxyTracerProvideris an internal class, and@delegateis not a public API. The specs define the same private ivar, so they will not detect a future implementation change. Isolate this compatibility check and test it against each supportedopentelemetry-apiversion.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@react_on_rails_pro/lib/react_on_rails_pro/open_telemetry.rb` around lines 194 - 201, Update default_proxy_provider? to avoid directly reading ProxyTracerProvider’s private `@delegate` instance variable; isolate the compatibility detection behind a dedicated helper or adapter using supported opentelemetry-api behavior, and update specs to exercise that compatibility check across each supported API version rather than defining the same private ivar.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@CHANGELOG.md`:
- Around line 29-35: Update the changelog entry describing Rails-to-Node
Renderer OpenTelemetry trace continuation by appending the PR link and author
attribution in the repository’s standard format, using the guidance from
changelog-guidelines.md and preserving the existing issue reference and
description.
In `@react_on_rails_pro/lib/react_on_rails_pro/renderer_http_client.rb`:
- Around line 186-198: Reset chunk_size at the start of each loop iteration in
MultipartBody#bytesize before conditionally assigning chunk.bytesize, so chunks
without a bytesize method cause the existing non-integer guard to return nil
rather than reusing a previous size.
---
Nitpick comments:
In `@react_on_rails_pro/lib/react_on_rails_pro/open_telemetry.rb`:
- Around line 194-201: Update default_proxy_provider? to avoid directly reading
ProxyTracerProvider’s private `@delegate` instance variable; isolate the
compatibility detection behind a dedicated helper or adapter using supported
opentelemetry-api behavior, and update specs to exercise that compatibility
check across each supported API version rather than defining the same private
ivar.
In `@react_on_rails_pro/lib/react_on_rails_pro/renderer_http_client.rb`:
- Around line 201-231: The WritableBody lifecycle currently seals the trace only
in close_write, so aborts through WritableBody#close leave ClientSpan
unfinished. Override WritableBody#close to invoke the parent close and ensure
`@trace`&.seal_request_size runs, then add a regression test covering
Output#close(error) and confirming the trace is sealed.
In `@react_on_rails_pro/spec/react_on_rails_pro/open_telemetry_spec.rb`:
- Around line 66-76: Update install_open_telemetry and the matching setup blocks
around the other reported locations to stub OpenTelemetry.tracer_provider and
OpenTelemetry.propagation with RSpec allow(...).to receive(...), rather than
defining singleton methods directly. Preserve the existing fake provider and
propagator return values while ensuring RSpec restores the real OpenTelemetry
behavior after each example.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: c295d5f6-99d2-4883-aa71-93d585a2be66
📒 Files selected for processing (12)
CHANGELOG.mddocs/pro/node-renderer.mddocs/pro/updating.mdreact_on_rails_pro/app/helpers/react_on_rails_pro_helper.rbreact_on_rails_pro/lib/react_on_rails_pro/concerns/async_rendering.rbreact_on_rails_pro/lib/react_on_rails_pro/concerns/stream.rbreact_on_rails_pro/lib/react_on_rails_pro/open_telemetry.rbreact_on_rails_pro/lib/react_on_rails_pro/renderer_http_client.rbreact_on_rails_pro/lib/react_on_rails_pro/stream_request.rbreact_on_rails_pro/sig/react_on_rails_pro/open_telemetry.rbsreact_on_rails_pro/sig/react_on_rails_pro/renderer_http_client.rbsreact_on_rails_pro/spec/react_on_rails_pro/open_telemetry_spec.rb
| def default_proxy_provider?(provider) | ||
| return false unless defined?(::OpenTelemetry::Internal::ProxyTracerProvider) | ||
| return false unless provider.instance_of?(::OpenTelemetry::Internal::ProxyTracerProvider) | ||
|
|
||
| # The API has no public configured-provider predicate. Reading the delegate avoids allocating a ProxyTracer on | ||
| # every no-SDK call. | ||
| !provider.instance_variable_get(:@delegate) | ||
| end |
There was a problem hiding this comment.
Fragile reliance on a private opentelemetry-api ivar, with zero coverage against the real gem.
def default_proxy_provider?(provider)
return false unless defined?(::OpenTelemetry::Internal::ProxyTracerProvider)
return false unless provider.instance_of?(::OpenTelemetry::Internal::ProxyTracerProvider)
!provider.instance_variable_get(:@delegate)
endThis is the sole gate deciding whether tracing activates at all, and it depends on reading @delegate off opentelemetry-api's Internal::ProxyTracerProvider — an undocumented implementation detail with no public accessor (as the neighboring comment acknowledges). Two things compound the risk:
opentelemetry-api/opentelemetry-sdkaren't added as even a development dependency anywhere inreact_on_rails_pro/(checked gemspec,Gemfile,Gemfile.development_dependencies, dummyGemfile), so this is never exercised against the real gem in CI.open_telemetry_spec.rbonly exercises this via hand-rolledstub_const/Class.newfakes (install_open_telemetry_constants) that encode the same@delegate-ivar assumption being tested — so the spec can't catch drift if the real gem's internal representation changes.- Every public entry point here (
start_client_span,capture_context, etc.) swallowsStandardErrorsilently, so if the ivar name/shape ever changes upstream, tracing just permanently no-ops with no error, warning, or failing test to surface it — it'll look identical to "OpenTelemetry not configured."
Worth at least a smoke test that loads the real opentelemetry-api gem (even just as a dev dependency for this spec file) and asserts default_proxy_provider? behaves as expected against OpenTelemetry::SDK.configure, so a future gem upgrade that changes this internal breaks CI instead of shipping a silent no-op.
There was a problem hiding this comment.
Not changed. There is no public configured-provider predicate, and adding an OpenTelemetry dependency is explicitly outside this task. The private delegate read is required to keep the absent/default-provider path allocation-free; API-faithful tests cover both the default proxy and a configured delegate, and the code comment records the upstream constraint.
Review: Pro OpenTelemetry propagation restorationWent through Not inline-able: async-props task fiber doesn't get OTel context propagated (
|
|
+ci-status |
CI StatusHead SHA: Only the required gate is active unless hosted CI is requested. |
| while index < @chunks.length | ||
| chunk = @chunks[index] | ||
| chunk_size = chunk.bytesize if chunk.respond_to?(:bytesize) | ||
| return unless chunk_size.is_a?(Integer) |
There was a problem hiding this comment.
Correctness / data-integrity: MultipartBody#bytesize silently reports 0 for the whole upload if any single chunk lacks a measurable size.
def bytesize
total = 0
index = 0
while index < @chunks.length
chunk = @chunks[index]
chunk_size = chunk.bytesize if chunk.respond_to?(:bytesize)
return unless chunk_size.is_a?(Integer) # <-- bare `return` here
total += chunk_size
index += 1
end
total
endThe bare return (returns nil) fires as soon as one chunk's bytesize isn't an Integer, discarding the sum already accumulated from every other chunk (boundary strings, headers, other file parts). MultipartFileBody#bytesize (a few lines above) itself returns nil whenever the wrapped IO doesn't respond to #size (e.g. a pipe, socket, or a custom uploadable that only implements #read). In that case OpenTelemetry.body_size maps the nil to 0, so the http.request.body.size span attribute for an asset upload silently reports 0 instead of the aggregate of everything that was measurable — misleading telemetry for exactly the case (bundle/asset uploads) this PR is trying to make observable.
Failure scenario: an asset upload where value[:body] is an IO-like object without #size → the whole multipart body's bytesize becomes nil → span records http.request.body.size = 0 even though megabytes were sent.
Suggest treating an unmeasurable chunk as contributing 0 (next instead of return) so the rest of the sum survives.
There was a problem hiding this comment.
Not changed. nil intentionally means the complete multipart size is unknown; summing only measurable chunks would publish a false partial total as the full request size. All in-tree multipart chunks are currently measurable, and the regression example preserves correct behavior for future unsupported chunks.
|
|
||
| # The API has no public configured-provider predicate. Reading the delegate avoids allocating a ProxyTracer on | ||
| # every no-SDK call. | ||
| !provider.instance_variable_get(:@delegate) |
There was a problem hiding this comment.
Altitude: silent-failure coupling to a private opentelemetry-api instance variable.
def default_proxy_provider?(provider)
return false unless defined?(::OpenTelemetry::Internal::ProxyTracerProvider)
return false unless provider.instance_of?(::OpenTelemetry::Internal::ProxyTracerProvider)
!provider.instance_variable_get(:@delegate)
endThis is the gate that decides whether the entire feature this PR restores (Rails→Node Renderer trace propagation) is active. It's implemented by reaching into the private @delegate ivar of OpenTelemetry::Internal::ProxyTracerProvider, which the comment itself acknowledges has no public "is the SDK configured" predicate.
Failure scenario: a future opentelemetry-api release renames or removes @delegate (or restructures ProxyTracerProvider entirely). instance_variable_get doesn't raise on a missing ivar — it just returns nil, so !nil → true, default_proxy_provider? always returns true, and configured_tracer_provider returns nil unconditionally. Tracing then silently no-ops for every request — no exception, no log line, nothing in CI unless a test pins the exact gem internals — even though the Rails app has fully configured OpenTelemetry. That's a quiet regression of the very feature this PR exists to restore, with no signal to operators.
Worth at least a version constraint on opentelemetry-api in the gemspec, or a one-time startup log if this heuristic can't classify the provider, so the failure is observable instead of silent.
There was a problem hiding this comment.
Not changed. OpenTelemetry exposes no public configured-provider predicate, and this task forbids adding a gem dependency. The private read is documented and covered by API-faithful default-proxy and configured-delegate tests while preserving the required allocation-free disabled path.
| final_request_size = ReactOnRailsPro::OpenTelemetry.body_size(@request_body) | ||
| @request_size = [@request_size, final_request_size].max | ||
| @span.set_attribute(REQUEST_SIZE_ATTRIBUTE, @request_size) | ||
| @span.set_attribute(RESPONSE_SIZE_ATTRIBUTE, @response_size) |
There was a problem hiding this comment.
Simplification: finish redundantly recomputes the same body_size/max calculation seal_request_size already did.
def seal_request_size
final_request_size = ReactOnRailsPro::OpenTelemetry.body_size(@request_body)
@request_size = [@request_size, final_request_size].max
@request_sealed = true
finish_if_ready
end
...
def finish
begin
final_request_size = ReactOnRailsPro::OpenTelemetry.body_size(@request_body)
@request_size = [@request_size, final_request_size].max
@span.set_attribute(REQUEST_SIZE_ATTRIBUTE, @request_size)
...Whenever the request side seals first (the WritableBody/bidi path), seal_request_size computes body_size(@request_body) and maxes it in; then once the response also finishes, finish_if_ready calls finish, which recomputes the exact same body_size(@request_body)/max a second time against an unchanged @request_body. It's harmless today (the .max makes it idempotent), but it's duplicated logic in two places that has to be kept in sync — a future change to how request size is measured only in one of them silently diverges from the other. Consider having finish just use @request_size as-is when the body was already sealed, or factoring the compute-and-max step into one shared private method.
There was a problem hiding this comment.
Not changed. The second measurement is intentional defensive accounting: the request body can be consumed after an earlier observation, and max preserves the largest complete measurement across normal, streamed, and multipart bodies. The current lifecycle tests verify the final recorded size.
| @request_sealed = true | ||
| @response_finished = false | ||
| @finished = false | ||
| @finish_mutex = Mutex.new |
There was a problem hiding this comment.
Simplification: three booleans + a mutex to express "finish once both halves are done."
@request_sealed = true
@response_finished = false
@finished = false
@finish_mutex = Mutex.newClientSpan tracks @request_sealed, @response_finished, and @finished (plus @finish_mutex) just to gate a single finish call on "both the request write and the response read completed." This works, but it's more state than the invariant needs — e.g. a single countdown counter (start at 2, decrement per completed side under the mutex, call finish at 0) would express the same rule with one field instead of three, and would make it obvious to a future maintainer exactly what "ready" means instead of requiring them to trace the three-way next false if @finished || !@request_sealed || !@response_finished condition in finish_if_ready. Not incorrect as written, just more surface area than necessary for a two-party join.
There was a problem hiding this comment.
Not changed. The explicit request-sealed, response-finished, and finished states make duplicate notifications idempotent and keep the two-phase lifecycle readable. A countdown would still need duplicate-event protection and synchronization, so it would not reduce the invariant materially.
|
+ci-run-hosted |
Hosted CI RequestedTriggered 9 workflow(s) for View progress in the Actions tab. |
|
|
||
| # The API has no public configured-provider predicate. Reading the delegate avoids allocating a ProxyTracer on | ||
| # every no-SDK call. | ||
| !provider.instance_variable_get(:@delegate) |
There was a problem hiding this comment.
default_proxy_provider? distinguishes "SDK configured" from "no SDK" by reading the private @delegate ivar of OpenTelemetry::Internal::ProxyTracerProvider — an undocumented implementation detail of the opentelemetry-api gem, not part of its public contract. The comment acknowledges there's no public predicate for this, which is a reasonable trade-off, but note the risk: since react_on_rails_pro doesn't depend on opentelemetry-api (by design, per the docs), this path is only exercised in this repo's specs via stub_const/fakes (see open_telemetry_spec.rb), never against the real gem. If a future opentelemetry-api release renames/restructures ProxyTracerProvider's internals, instance_variable_get(:@delegate) would silently return nil, default_proxy_provider? would incorrectly report true even when an SDK is configured, and tracing would silently stop working for consuming apps — with no signal in this repo's CI to catch it.
Worth considering: a lightweight CI job (or even a local dev dependency) that runs the spec suite against a real opentelemetry-sdk/opentelemetry-api install occasionally, to catch drift in this private API early — matching the "Follow-ups" note already in the PR description about needing real-SDK integration coverage.
There was a problem hiding this comment.
Agreed on the integration gap, and no tracked change is made here because this task intentionally forbids an OpenTelemetry dependency. The PR Follow-ups section records a real-SDK cross-runtime continuity test for the first point after the parallel Node-side implementation lands.
| return 0 unless body | ||
|
|
||
| size = body.bytesize if body.respond_to?(:bytesize) | ||
| size.is_a?(Integer) ? size : 0 |
There was a problem hiding this comment.
Minor observability-accuracy nit: when a body responds to bytesize but returns a non-Integer (e.g. nil, as MultipartFileBody#bytesize can for a chunk with no determinate size — see the new "returns an unknown size when a multipart chunk has no byte size" spec in renderer_http_client_spec.rb), this collapses to 0 rather than leaving the size attribute unset/unknown. A 0-byte http.request.body.size/http.response.body.size on a span reads as "empty request," which is misleading when the true size is simply indeterminate (e.g. an upload chunk backed by a custom IO-like object without a fixed size). Not a functional bug — just something that could send someone down the wrong path when debugging payload sizes from trace data. Could consider omitting the attribute entirely (set_attribute not called) when size is unknown, rather than defaulting to 0.
There was a problem hiding this comment.
Not changed for this scope. The task requires request and response byte-size attributes, while an unsupported complete size cannot be represented as a partial total without implying false precision. Current renderer request bodies are measurable; the new regression test ensures future unsupported bodies are classified consistently rather than reusing stale size data.
Review: Pro OpenTelemetry trace propagation restorationReviewed with a focus on code quality, correctness/bugs, security, and performance. Overall this is a careful, well-tested implementation — I traced through the fiber/context-propagation logic ( Security / privacy: looks sound. Only Performance: the "allocation-free no-op on the hot path" claim is verified by dedicated specs for both the no-OTel and default-proxy-provider cases, and the code path backs that up ( Two minor, non-blocking points left as inline comments:
Neither blocks merge; both are refinements for future hardening. Nice work restoring this after the async-http migration, and good foresight calling out the real-SDK integration test gap in the PR description's Follow-ups section. |
|
+ci-status |
CI StatusHead SHA: Optimized hosted CI is enabled for this PR. |
4abcb81 to
6caf763
Compare
6caf763 to
29a34a5
Compare
Summary
Restores Rails-side OpenTelemetry CLIENT spans and W3C trace propagation for Node Renderer requests after the async-http migration. This reconnects regular, streaming, incremental, raw-render, and asset-upload work to the Rails trace while keeping OpenTelemetry optional and protecting payload privacy.
Closes #4866.
@AbanoubGhadban, this restores the propagation behavior lost during the transport migration in #3320.
Pull Request checklist
Other Information
Labels: ready-for-hosted-ci. The change affects shared Pro renderer request paths and should receive optimized hosted CI after local review.
Benchmarks: not applicable. The disabled telemetry path is constrained by allocation regression coverage, and this change does not alter rendering computation.
Follow-ups
Summary by CodeRabbit