Skip to content

refactor(ts): assemble spans directly, dropping the OpenTelemetry SDK - #77

Open
kozlek wants to merge 1 commit into
devs/kozlek/thomasberdy/mrgfy-8439-rust-api-client/upload-traces-rust-client--314107d7from
devs/kozlek/thomasberdy/mrgfy-8439-rust-api-client/assemble-spans-directly-dropping-opentelemetry-sdk--f702a313
Open

refactor(ts): assemble spans directly, dropping the OpenTelemetry SDK#77
kozlek wants to merge 1 commit into
devs/kozlek/thomasberdy/mrgfy-8439-rust-api-client/upload-traces-rust-client--314107d7from
devs/kozlek/thomasberdy/mrgfy-8439-rust-api-client/assemble-spans-directly-dropping-opentelemetry-sdk--f702a313

Conversation

@kozlek

@kozlek kozlek commented Aug 6, 2026

Copy link
Copy Markdown
Collaborator

The trace upload moved to the Rust client in the commit below this one, but
spans were still built on the OpenTelemetry SDK and marshalled from
ReadableSpans by a SpanExporter shim. That shim and the SDK behind it are
gone: @mergifyio/ci-core now assembles the binding's plain span records
directly, as pytest-mergify already does.

@mergifyio/ci-core is left with exactly one runtime dependency — the binding.
@opentelemetry/{api,core,resources,sdk-trace-base} are dropped from all three
packages.

Ported from the SDK, mirroring pytest-mergify's tracing.py so the semantics
are shared rather than re-derived:

  • trace/span id generation,
  • W3C traceparent parsing for MERGIFY_TRACEPARENT, keeping the propagator's
    rejection rules — bad widths, uppercase or non-hex, all-zero ids, and the
    reserved ff version,
  • span parenting, now an explicit parent id rather than an active context,
  • resource attributes as a plain record.

Timestamps are the one place this is more than a transcription. Epoch
nanoseconds are ~1.7e18, past what a JS number holds exactly, so msToUnixNano
converts the whole and fractional parts separately in BigInt. A naive
ms * 1e6 would silently lose precision.

tracerName is dropped rather than ported: it set the OTLP instrumentation
scope, and the Rust uploader sends scope: None, so it has been inert on the
wire since trace upload moved to the client. Removing it changes no emitted
bytes.

The test seam

The behavior suites captured spans through an injected SpanExporter. That
option becomes sink, a SpanSink — renamed rather than retyped in place,
because silently changing what a public option accepts is worse than breaking
it. InMemorySpanSink replaces InMemorySpanExporter and exposes the same
getFinishedSpans(), with attributes keyed rather than listed, which is what
the assertions actually read.

These suites are the parity gate for the whole MRGFY-8439 migration, so they
were ported assertion-for-assertion, not re-derived: same span names,
attributes, statuses, parenting and counts. Playwright stayed at 105 tests and
vitest at 20 — unchanged totals, passing against an implementation that shares
no code with the one they were written for.

Two honest deltas in spans.test.ts: the "propagates forceFlush errors while
still attempting shutdown" case becomes "propagates an upload failure", since
there is no provider to shut down; and new cases cover the buffer draining on
export and the resource attributes riding along. trace-context.test.ts covers
the newly hand-written traceparent parsing and nanosecond conversion.

Fixes MRGFY-8513
Related to MRGFY-8439

Co-Authored-By: Claude Opus 5 (1M context) noreply@anthropic.com

Depends-On: #76

@kozlek

kozlek commented Aug 6, 2026

Copy link
Copy Markdown
Collaborator Author

This pull request is part of a Mergify stack:

# Pull Request Link
1 refactor(ts): upload traces through the Rust client #76
2 refactor(ts): assemble spans directly, dropping the OpenTelemetry SDK #77 👈

@mergify

mergify Bot commented Aug 6, 2026

Copy link
Copy Markdown

Merge Protections

🔴 3 of 7 protections blocking · waiting on 👀 reviews and ⛓️ dependency

Protection Waiting on
🔴 ⛓️ Depends-On Requirements ⛓️ dependency
🔴 👀 Review Requirements 👀 reviews
🔴 🔎 Reviews 👀 reviews
🟢 🤖 Continuous Integration
🟢 Enforce conventional commit
🟢 📕 PR description
🟢 🚦 Auto-queue

🔴 ⛓️ Depends-On Requirements

Waiting for

This rule is failing.

Requirement based on the presence of Depends-On in the body of the pull request

🔴 👀 Review Requirements

Waiting for

  • #approved-reviews-by>=2
This rule is failing.
  • any of:
    • #approved-reviews-by>=2
    • author = dependabot[bot]
    • author = mergify-ci-bot
    • author = renovate[bot]

🔴 🔎 Reviews

Waiting for

  • #review-requested = 0
This rule is failing.
  • #review-requested = 0
  • #changes-requested-reviews-by = 0
  • #review-threads-unresolved = 0

Show 4 satisfied protections

🟢 🤖 Continuous Integration

  • all of:
    • check-success=ci-gate

🟢 Enforce conventional commit

Make sure that we follow https://www.conventionalcommits.org/en/v1.0.0/

  • title ~= ^(fix|feat|internal|docs|style|refactor|perf|test|build|ci|chore|revert|ui)(?:\(.+\))?!?:

🟢 📕 PR description

  • body ~= (?ms:.{48,})

🟢 🚦 Auto-queue

When all merge protections are satisfied, this pull request will be queued automatically.

@kozlek
kozlek marked this pull request as ready for review August 6, 2026 17:31
@kozlek
kozlek force-pushed the devs/kozlek/thomasberdy/mrgfy-8439-rust-api-client/assemble-spans-directly-dropping-opentelemetry-sdk--f702a313 branch from 963bc8c to 779f607 Compare August 10, 2026 12:12
@kozlek

kozlek commented Aug 10, 2026

Copy link
Copy Markdown
Collaborator Author

Revision history

# Type Changes Reason Date
1 initial 963bc8c 2026-08-10 12:12 UTC
2 rebase 963bc8c → 779f607 (rebase only) 2026-08-10 12:12 UTC
3 rebase 779f607 → dbda989 (rebase only) 2026-08-11 15:50 UTC

@mergify
mergify Bot had a problem deploying to Mergify Merge Protections August 10, 2026 12:13 Failure
@mergify
mergify Bot requested a review from a team August 10, 2026 12:15
The trace upload moved to the Rust client in the commit below this one, but
spans were still built on the OpenTelemetry SDK and marshalled from
`ReadableSpan`s by a `SpanExporter` shim. That shim and the SDK behind it are
gone: `@mergifyio/ci-core` now assembles the binding's plain span records
directly, as pytest-mergify already does.

`@mergifyio/ci-core` is left with exactly one runtime dependency — the binding.
`@opentelemetry/{api,core,resources,sdk-trace-base}` are dropped from all three
packages.

Ported from the SDK, mirroring pytest-mergify's `tracing.py` so the semantics
are shared rather than re-derived:

* trace/span id generation,
* W3C `traceparent` parsing for `MERGIFY_TRACEPARENT`, keeping the propagator's
  rejection rules — bad widths, uppercase or non-hex, all-zero ids, and the
  reserved `ff` version,
* span parenting, now an explicit parent id rather than an active context,
* resource attributes as a plain record.

Timestamps are the one place this is more than a transcription. Epoch
nanoseconds are ~1.7e18, past what a JS number holds exactly, so `msToUnixNano`
converts the whole and fractional parts separately in BigInt. A naive
`ms * 1e6` would silently lose precision.

`tracerName` is dropped rather than ported: it set the OTLP instrumentation
scope, and the Rust uploader sends `scope: None`, so it has been inert on the
wire since trace upload moved to the client. Removing it changes no emitted
bytes.

## The test seam

The behavior suites captured spans through an injected `SpanExporter`. That
option becomes `sink`, a `SpanSink` — renamed rather than retyped in place,
because silently changing what a public option accepts is worse than breaking
it. `InMemorySpanSink` replaces `InMemorySpanExporter` and exposes the same
`getFinishedSpans()`, with attributes keyed rather than listed, which is what
the assertions actually read.

These suites are the parity gate for the whole MRGFY-8439 migration, so they
were ported assertion-for-assertion, not re-derived: same span names,
attributes, statuses, parenting and counts. Playwright stayed at 105 tests and
vitest at 20 — unchanged totals, passing against an implementation that shares
no code with the one they were written for.

Two honest deltas in `spans.test.ts`: the "propagates forceFlush errors while
still attempting shutdown" case becomes "propagates an upload failure", since
there is no provider to shut down; and new cases cover the buffer draining on
export and the resource attributes riding along. `trace-context.test.ts` covers
the newly hand-written traceparent parsing and nanosecond conversion.

Fixes MRGFY-8513
Related to MRGFY-8439

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Change-Id: If702a3137ce305d18f35afff305cad4545eeb4a1
@kozlek
kozlek force-pushed the devs/kozlek/thomasberdy/mrgfy-8439-rust-api-client/assemble-spans-directly-dropping-opentelemetry-sdk--f702a313 branch from 779f607 to dbda989 Compare August 11, 2026 15:50
@mergify
mergify Bot had a problem deploying to Mergify Merge Protections August 11, 2026 15:50 Failure
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant