diagnostics_channel: pass non-thenable tracePromise return values through - #33456
diagnostics_channel: pass non-thenable tracePromise return values through#33456robobun wants to merge 2 commits into
Conversation
|
Warning Review limit reached
Next review available in: 2 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (2)
Comment |
|
Updated 8:45 AM PT - Jul 6th, 2026
⏳ @robobun, your commit 2f2f873 is still building in
|
|
This PR may be a duplicate of:
🤖 Generated with Claude Code |
There was a problem hiding this comment.
LGTM — small, well-tested Node compat fix verified against upstream behavior.
Extended reasoning...
Overview
This PR fixes tracingChannel().tracePromise() in src/js/node/diagnostics_channel.ts to match Node.js semantics: when the wrapped function returns a non-thenable, the value is now passed through unchanged (with a process.emitWarning) instead of being coerced to a Promise and triggering spurious asyncStart/asyncEnd events. The logic change is ~10 lines; the rest is six new tests in test/js/node/diagnostics_channel/diagnostics_channel.test.ts replacing a test.todo placeholder.
Security risks
None. This is pure-JS diagnostics instrumentation with no auth, crypto, filesystem, or network surface. The only new side effect is a process.emitWarning call, which mirrors Node.
Level of scrutiny
Low-to-moderate. It's a focused Node-compat behavioral fix in a built-in JS module — no native code, no memory management, no cross-platform concerns. The previous behavior (always wrapping in Promise.resolve()) was clearly divergent from Node, and the new thenable check (typeof result?.then !== 'function') plus direct .then() invocation is the standard pattern Node uses. The finally block still publishes end on the non-thenable path, so event ordering is preserved.
Other factors
- Test coverage is thorough: non-thenable,
undefined, native promise, custom thenable (verifying return type is preserved), rejected promise, and synchronous throw — with the PR description stating every assertion was cross-checked against Node v26.3.0. - The now-unused
PromiseResolvebinding is cleaned up. - No CODEOWNERS entry covers this path, no outstanding reviewer comments, and the bug-hunting system found no issues.
|
The duplicate flag is accurate: #32628 (draft) contains this same The two converge on identical semantics for this method: the same What differs is scope and state. #32628 has been in draft since June 23, was last pushed June 29, and currently conflicts with main. This PR is ~10 lines in one method plus six tests. Happy to close this one if #32628 is close to landing. If it isn't, this fixes the reported behavior on its own, and whichever merges second should be a trivial conflict confined to that one method. |
…ough tracePromise() coerced whatever the traced function returned into a native promise, so a function returning a plain value handed its caller a Promise and published a zero-duration asyncStart/asyncEnd pair. Return non-thenables as-is with only start/end published, and emit the same process warning node does. Custom thenables now get .then() called directly so their type is preserved instead of being replaced by a native promise.
1a38899 to
2b1d0db
Compare
There was a problem hiding this comment.
LGTM — small, well-tested Node compat fix; the cookie-map CI failure is unrelated to this change.
Extended reasoning...
Overview
This PR changes ~10 lines in TracingChannel.prototype.tracePromise in src/js/node/diagnostics_channel.ts to match Node.js semantics: when the traced function returns a non-thenable, the value is passed through unchanged (with only start/end published and a process.emitWarning fired), and when it returns a thenable, .then() is called on it directly rather than coercing through Promise.resolve(). The now-unused PromiseResolve binding is removed. Six new tests replace the test.todo placeholder in the TracingChannel describe block, covering non-thenable, undefined, native promise, custom thenable, rejected promise, and synchronous throw — all cross-checked against Node v26.3.0 per the PR description.
Security risks
None. diagnostics_channel is an observability/instrumentation API with no auth, crypto, filesystem, or network surface. The change narrows behavior (stops wrapping values in promises) rather than expanding it.
Level of scrutiny
Low-to-moderate. This is a focused Node-compat correction in a built-in JS module, directly mirroring the upstream Node implementation (same typeof result?.then !== "function" predicate, same warning text). The duplicate-PR bot confirmed #32628 uses identical semantics for this method, which independently corroborates the approach. The finally { end.publish(context) } block is unchanged, so the sync-path event ordering (start, end) is preserved. Optional chaining on result?.then correctly handles null/undefined returns.
Other factors
- The CI failure is
test/js/bun/cookie/cookie-map.test.ts, which is unrelated to this diff and stems from the base branch (commit 48ff9eb on main touched cookie-map assertions). - The overlap with draft PR #32628 has already been surfaced and addressed by the author in-thread; whichever lands second has a trivial one-method conflict. That's a merge-order call, not a correctness concern.
- Tests use unique channel names per case, clean up the
warninglistener infinally, and assert exact event orderings and warning text — good coverage of the variant matrix. - No CODEOWNERS entry for this path.
There was a problem hiding this comment.
LGTM — small, well-tested Node compat fix that mirrors upstream tracePromise semantics.
Extended reasoning...
Overview
This PR touches two files: src/js/node/diagnostics_channel.ts (~10 lines of logic in TracingChannel.prototype.tracePromise plus a small emitNonThenableWarning helper and removal of the unused PromiseResolve binding) and test/js/node/diagnostics_channel/diagnostics_channel.test.ts (six new tests replacing a test.todo placeholder). The fix changes tracePromise to detect non-thenable return values via typeof result?.then !== "function", pass them through unchanged with only the sync start/end events published, and emit the same process.emitWarning text Node emits. Thenables now have .then() called directly, preserving custom thenable types instead of coercing to a native Promise.
Security risks
None. This is pure JavaScript in a Node compat module with no auth, crypto, filesystem, or network surface. The only new observable side effect is a process.emitWarning call, which mirrors Node.
Level of scrutiny
Low-to-moderate. It's a Node.js compatibility fix in a built-in JS module — the reference implementation is Node itself, and the PR description states every assertion was verified against Node v26.3.0. The logic is a straightforward branch on thenable-ness; the finally { end.publish(context) } block is unchanged so the sync event ordering is preserved on all paths (non-thenable, thenable, and sync throw). No native code, no memory or GC concerns.
Other factors
Test coverage is thorough: non-thenable value, undefined, native promise, custom synchronous thenable, rejected promise, and synchronous throw — each asserting exact event ordering, context contents, and warning text. Tests clean up the process.on("warning") listener in finally. The overlap with draft PR #32628 has already been surfaced and addressed by the author; whichever lands second is a trivial conflict in one method. No CODEOWNERS entry covers this path and no outstanding reviewer comments are pending.
CI status: the diff is green, the red lanes are unrelatedBuild 69079 finished at 242 passed, 1 failed. Build 68851 ( Build 69053 ( Build 69079 (
Tests that failed and then passed on retry in that build ( I've used my one re-roll (the |
tracingChannel().tracePromise(fn, ctx)with a function that returns a non-thenable wrapped the return value in a promise and published a spuriousasyncStart/asyncEndpair.Node's documented contract is that a non-promise return value is passed through as-is and only the sync events are published; the async phase is reserved for actual promise settlement. This matters because diagnostics_channel instrumentation wraps existing functions that may have a sync fast path, and on Bun that wrapper changed the function's return type from a value to a promise.
Repro
Cause
tracePromisecoerced the callback's return value withPromise.resolve()before chaining onto it:So every return value became a promise, and
resolve/reject(which publish the async events) always ran.Fix
In
src/js/node/diagnostics_channel.ts, branch on whether the return value is thenable:context.result, publishend, return the value unchanged, and emit the sameprocess.emitWarningnode emits (tracePromise was called with the function 'x', which returned a non-thenable.).then(resolve, reject)on it directly, which preserves the type of custom thenables rather than replacing them with a native promiseThe now-unused
PromiseResolvebinding is removed.Verification
Six
tracePromisetests added totest/js/node/diagnostics_channel/diagnostics_channel.test.ts, covering the non-thenable return,undefinedreturn, native promise, custom thenable, rejected promise, and a synchronous throw. Every assertion was first run against node v26.3.0 (the version Bun reports asprocess.versions.node) so the expected return values, event orderings,contextcontents, and warning text match node exactly.Three of the six fail on current
main; all six pass with the fix. The vendoredtest-diagnostics-channel-*tests intest/js/node/test/parallel/still pass.