Skip to content

fix(do): propagate the inbound sampled bit instead of hardcoding it - #191

Merged
prisis merged 2 commits into
alphafrom
fix/trace-sampled-propagation
Jul 25, 2026
Merged

fix(do): propagate the inbound sampled bit instead of hardcoding it#191
prisis merged 2 commits into
alphafrom
fix/trace-sampled-propagation

Conversation

@prisis

@prisis prisis commented Jul 25, 2026

Copy link
Copy Markdown
Member

What

createTracedFetch set the sampled flag on every outbound traceparent to a
literal true:

request.headers.set("traceparent", buildTraceparent(anchor.traceId, spanId, true));

parseTraceparent already reads the inbound bit, but resolveTraceAnchor
discarded it — so a trace an upstream had sampled out was announced to every
callee as sampled in.

Why it matters

The callee records and exports spans for a trace nobody kept. The collector gets
a fragment with no root and no siblings, and the sampling decision the upstream
made is silently not the decision the system applied — the exact failure the
flag exists to prevent.

The runtime's own propagation (otel-trace.ts:197) already threaded
trace.sampled correctly. Only the shard path diverged, so worker-originated
and shard-originated hops of the same trace disagreed.

The fix

The verdict rides on the TraceAnchor, resolved once per dispatch, so every
ctx.fetch of one dispatch propagates one consistent answer rather than each
deriving its own.

A dispatch with no inbound traceparent — a subscription re-run, a
server-initiated call — still samples: it is the trace root, so there is no
upstream verdict to inherit.

Tests

  • traced-fetch.test.ts — both directions through ctx.fetch
  • trace-context.test.ts (new) — the anchor inheriting, defaulting, and
    rejecting a malformed inbound header

Both halves are mutation-verified: restoring the hardcoded true, or making the
anchor ignore the inbound verdict, each fail a test. @lunora/do 1245 passing,
@lunora/runtime 741 passing.

Scope

Deliberately one fix. This was extracted by content from
feat/platform-abstraction-layer (#190); everything else OTel-related on that
branch either already exists on alpha (resource detection, tail-sampler
reporting, fail-closed redaction, the createOtelTracer bridge as
@lunora/server/otel) or is structural divergence with no behavioural benefit.
This was the only genuine bug that alpha still carries.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes
    • Improved distributed tracing to preserve the inbound trace’s sampling decision across outbound requests.
    • Prevented downstream spans from being recorded when the originating trace was not sampled.
    • Reduced orphaned telemetry data and improved trace consistency across connected services.

`createTracedFetch` set every outbound `traceparent`'s sampled flag to
`true`. `parseTraceparent` already reads the inbound bit and
`resolveTraceAnchor` threw it away, so a trace an upstream had sampled
OUT was announced to every callee as sampled in.

The callee then records and exports spans for a trace nobody kept. The
collector receives a fragment with no root and no siblings, and the
sampling decision the upstream made is silently not the one the system
applied — which is the exact failure the flag exists to prevent.

The verdict now rides on the `TraceAnchor`, resolved once per dispatch,
so every `ctx.fetch` of one dispatch propagates one consistent answer
rather than each deriving its own. A dispatch with no inbound
`traceparent` — a subscription re-run, a server-initiated call — still
samples: it is the trace root, so there is no upstream verdict to
inherit.

The runtime's own propagation (`otel-trace.ts`) already threaded
`trace.sampled` correctly; only the shard path diverged.

Tests: both directions through `ctx.fetch`, plus `resolveTraceAnchor`
inheriting, defaulting, and rejecting a malformed inbound header. Both
halves are mutation-verified — restoring the hardcoded `true`, or making
the anchor ignore the inbound verdict, each fail a test.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@netlify

netlify Bot commented Jul 25, 2026

Copy link
Copy Markdown

Deploy Preview for lunorash ready!

Name Link
🔨 Latest commit 1441bf4
🔍 Latest deploy log https://app.netlify.com/projects/lunorash/deploys/6a6510769ea6aa00089671b7
😎 Deploy Preview https://deploy-preview-191--lunorash.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
🤖 Make changes Run an agent on this branch

To edit notification comments on pull requests, go to your Netlify project configuration.

@coderabbitai

coderabbitai Bot commented Jul 25, 2026

Copy link
Copy Markdown

Review Change Stack

Important

Review skipped

Review was skipped due to path filters

⛔ Files ignored due to path filters (1)
  • api-snapshots/do.api.md is excluded by none and included by none

CodeRabbit blocks several paths by default. You can override this behavior by explicitly including those paths in the path filters. For example, including **/dist/** will override the default block on the dist directory, by removing the pattern from both the lists.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 24036c7f-a467-4d6e-82c8-5c1fec8b2fff

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Walkthrough

Tracing now preserves the inbound W3C traceparent sampling verdict in TraceAnchor and applies it to outbound ctx.fetch propagation. New trace contexts default to sampled.

Changes

Traceparent Sampling Propagation

Layer / File(s) Summary
Resolve sampled trace context
packages/do/src/trace-context.ts
resolveTraceAnchor returns sampled, preserving the inbound verdict or defaulting to true when no inbound traceparent exists.
Propagate sampled anchor state
packages/do/src/context-telemetry.ts
TraceAnchor stores the optional sampling flag, and outbound traceparent headers use it instead of always setting sampling to true.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related PRs

  • anolilab/lunora#166: Implements related traceparent sampled-flag propagation through RPC dispatch and span export.
  • anolilab/lunora#189: Introduces earlier createTracedFetch and traceparent propagation work in the same tracing pipeline.
  • anolilab/lunora#143: Wires forwarded traceparent headers through worker, ShardDO, and container tracing.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description is detailed, but it misses required template sections and the exact CLA statement. Add the required Summary, Linked issues, Test plan, Checklist, Notes for reviewers, and the exact CLA statement from the template.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title is concise, conventional-commit style, and accurately describes the sampled-bit propagation change.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/trace-sampled-propagation

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

Copy link
Copy Markdown
Contributor

Thank you for following the naming conventions! 🙏

@github-actions

Copy link
Copy Markdown
Contributor

Thank you for confirming the Contributor License Agreement! 🙏

@codspeed-hq

codspeed-hq Bot commented Jul 25, 2026

Copy link
Copy Markdown

Merging this PR will regress 1 benchmark

⚠️ Different runtime environments detected

Some benchmarks with significant performance changes were compared across different runtime environments,
which may affect the accuracy of the results.

Open the report in CodSpeed to investigate

⚡ 2 improved benchmarks
❌ 1 regressed benchmark
✅ 236 untouched benchmarks
⏩ 2 skipped benchmarks1

Warning

Please fix the performance issues or acknowledge them on CodSpeed.

Performance Changes

Benchmark BASE HEAD Efficiency
in-batch: single IN(...) query + id->doc re-projection 816.3 µs 948.4 µs -13.93%
low fanout — 5 sockets × 1 sub each, table match 73.2 µs 59.1 µs +23.94%
flat 3 primitives (the notify.send attribute shape) 62.2 µs 55.5 µs +12.1%

Tip

Investigate this regression by commenting @codspeedbot fix this regression on this PR, or directly use the CodSpeed MCP with your agent.


Comparing fix/trace-sampled-propagation (1441bf4) with alpha (49b10ad)2

Open in CodSpeed

Footnotes

  1. 2 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

  2. No successful run was found on alpha (b66b371) during the generation of this report, so 49b10ad was used instead as the comparison base. There might be some changes unrelated to this pull request in this report.

`TraceAnchor` is part of `@lunora/do`'s public surface, so adding the
`sampled` verdict drifts the committed snapshot. Optional, so it is
additive: an existing consumer constructing an anchor still compiles, and
a consumer reading one gets `boolean | undefined` — which is why the
propagation path treats an absent verdict as "sampled" rather than
assuming the field is always present.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@prisis
prisis merged commit 4ebb86a into alpha Jul 25, 2026
41 of 42 checks passed
@prisis
prisis deleted the fix/trace-sampled-propagation branch July 25, 2026 19:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant