fix(e2e): assert on the gen-AI span that served the stream, not the span count - #36582
Conversation
|
|
Greptile SummaryThe current head updates streaming OTEL e2e assertions to select the non-error gen-AI span that served a retried request rather than requiring one raw attempt span.
Confidence Score: 5/5The PR appears safe to merge. No blocking failure remains.
|
| Filename | Overview |
|---|---|
| tests/e2e/logging/test_otel_trace_e2e.py | Replaces raw gen-AI span-count assertions with served-attempt selection across streaming trace and TTFT checks; no eligible follow-up defect was established. |
| tests/e2e/logging/test_span_selection.py | Adds focused fixture-based coverage for the span-selection helper, including retries and duplicate served spans; no eligible follow-up defect was established. |
Reviews (2): Last reviewed commit: "fix(e2e): assert on the gen-AI span that..." | Re-trigger Greptile
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
…pan count The otel trace tests asserted that a streamed call produces exactly one gen-AI span. The proxy opens one gen-AI span per upstream attempt, so a call the router retried carries an error span for every failed attempt beside the one that answered, and the assertion fails on a request that succeeded. Select the served attempt instead: drop spans whose otel.status_code is ERROR, require exactly one survivor, and run the TTFT and streaming-flag assertions against it. That keeps what these assertions exist for, a split trace or a stream logged as two served spans, while tolerating a retry. Only the failed attempt lacks TTFT, so the old code also had a second failure mode: when the first span happened to be the error one, the test reported the attribute as missing rather than as belonging to a different attempt. test_span_selection.py covers the selection itself against Jaeger-shaped payloads and carries no e2e marker, since reproducing a first-attempt failure live is not something a test can arrange.
c7f9da4 to
c881b14
Compare
|
@greptileai the 5/5 was against c7f9da4, which a force-push replaced. Please re-review the current head c881b14 |
a0d499e
into
litellm_internal_staging
TLDR
Problem this solves:
How it solves it:
User Flow
This PR changes only
tests/e2e, so no end user's behavior changes. The flow below is the engineer reading the nightly e2e report.Before: a nightly run goes red on a request the gateway served correctly, so the report says the otel integration is broken when it is not
"stream": trueagainstclaude-haiku-4-5chat claude-haiku-4-5spans, one per attemptAfter: the same run is green, and still red for the problem these tests were written to catch
"stream": trueRelevant issues
Linear ticket
Resolves LIT-5441
Pre-Submission checklist
Please complete all items before asking a LiteLLM maintainer to review your PR
@greptileaito re-request a review after pushing changes)Delays in PR merge?
If you're seeing a delay in your PR being merged, ping the LiteLLM Team on Slack (#pr-review).
Screenshots / Proof of Fix
Both legs ran against the same live gateway from a pod built from the nightly's own e2e image, same four tests, same command, back to back.
Before, at base commit
bea31871fc(the file straight out ofgit show HEAD:..., asserted to not contain the fix before running):That is the nightly's failure reproduced, and rounds 2 and 3 passing is the intermittency.
Reading that trace out of the trace store shows the two spans are one request, not a split trace:
After, same gateway, same command, fifteen rounds: nine at
c7f9da4e5eand six more atc881b1426f, which renamed two helpers so the harness type gate would accept the cross-module import and changed nothing else. The staged file is greped first so an after leg cannot silently be running the base code:90 passes with no failure, against a 17.5% per-call retry rate on this gateway.
Mutation check on the new selection logic, each mutant applied and run separately, every mutation step self-verifying that it changed the source:
Type
🐛 Bug Fix
✅ Test
Caveats (if any)
QA runbook
tests/e2e/logging/test_otel_trace_e2e.py::TestOtelTraceCompleteness::test_messages_stream_records_real_ttft - a streamed /v1/messages call records a real time-to-first-token on the attempt that served it, even when an earlier attempt failed
num_retries: 3"stream": true, repeating until the response 200s having burned an attempt on the bad deploymentchat <model>spans, one withotel.status_code=ERRORand no TTFT, one with a TTFT between 0 and its own durationtests/e2e/logging/test_span_selection.py - the span selection itself, over trace payloads, with no proxy involved
otel.status_codefilter and expect 3 failures== 1to>= 1and expect test_two_served_spans_still_fail to failFinal Attestation