Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 57 additions & 0 deletions docs/doctoring/opentelemetry-packaging-extra.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# OpenTelemetry packaging extra

## Operator action

Install the package-owned instrumentation API with the reviewed optional extra:

```bash
pip install 'pg-llm-batch[observability]'
```

This extra installs `opentelemetry-api>=1.44,<2` and does **not** install
`opentelemetry-sdk`. The base package remains OpenTelemetry-independent.
Applications that want exported telemetry must separately select, configure,
and operate a compatible SDK, resource attributes, processors or readers,
exporters, collector endpoints, sampling, credentials, and retention.

This separation follows the OpenTelemetry library-instrumentation boundary:
libraries depend on the API, while the embedding application owns the SDK and
emission pipeline. It also uses the Python packaging `optional-dependencies`
contract, which maps an extra to conditional `Requires-Dist` metadata rather
than silently widening every installation.

## Supply-chain and compatibility boundary

The `observability` extra is represented in `pyproject.toml`, the built
wheel/sdist metadata, and the repository `uv.lock`. The lock is generated and
verified with repository-pinned uv 0.12.3; it must not be hand edited. Clean
installation tests prove both directions:

- base wheel: `opentelemetry` is absent;
- `pg-llm-batch[observability]`: the OpenTelemetry API is present and
`pg_llm_batch.observability.OpenTelemetryBatchAPIClient` is importable.

`opentelemetry-sdk` remains a host deployment decision. Installing the package
extra alone is not evidence that telemetry is exported, retained, secured, or
compliant with any certification regime.

## Rollback

A host can remove package-level OpenTelemetry support by reinstalling the base
package without the extra. The host must separately remove or reconfigure any
SDK/exporter components it owns. Package rollback does not delete host telemetry
or change backend retention.

## References

OpenTelemetry Authors. (n.d.). *Instrumentation*. OpenTelemetry. Retrieved
August 14, 2026, from
https://opentelemetry.io/docs/languages/python/instrumentation/

Python Packaging Authority. (n.d.). *pyproject.toml specification*. Python
Packaging User Guide. Retrieved August 14, 2026, from
https://packaging.python.org/en/latest/specifications/pyproject-toml/

Python Packaging Authority. (n.d.). *Core metadata specifications*. Python
Packaging User Guide. Retrieved August 14, 2026, from
https://packaging.python.org/en/latest/specifications/core-metadata/
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ dependencies = [
]

[project.optional-dependencies]
observability = ["opentelemetry-api>=1.44,<2"]
secrets = ["cryptography>=50.0.0"]
test = [
"pytest>=7.4",
Expand Down
53 changes: 53 additions & 0 deletions tests/test_opentelemetry_optional_dependency.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# SPDX-License-Identifier: Apache-2.0
"""Contract tests for the first-class OpenTelemetry optional dependency."""

from __future__ import annotations

from pathlib import Path

try:
import tomllib
except ModuleNotFoundError: # pragma: no cover - Python 3.10
import tomli as tomllib


ROOT = Path(__file__).resolve().parents[1]
OBSERVABILITY_API_REQUIREMENT = "opentelemetry-api>=1.44,<2"


def _project_metadata() -> dict[str, object]:
"""Load the package metadata used by build and installation tooling."""
return tomllib.loads((ROOT / "pyproject.toml").read_text(encoding="utf-8"))[
"project"
]


def test_observability_extra_declares_api_only_dependency() -> None:
"""Package metadata exposes bounded API-only OpenTelemetry installation."""
project = _project_metadata()
extras = project["optional-dependencies"]

assert extras["observability"] == [OBSERVABILITY_API_REQUIREMENT]
assert not any(
requirement.startswith("opentelemetry-sdk")
for requirement in extras["observability"]
)


def test_base_runtime_remains_opentelemetry_independent() -> None:
"""The default install must not silently acquire telemetry dependencies."""
project = _project_metadata()
dependencies = project["dependencies"]

assert not any(
requirement.startswith("opentelemetry-") for requirement in dependencies
)


def test_observability_extra_has_one_explicit_runtime_requirement() -> None:
"""Keep the optional installation surface minimal and reviewable."""
project = _project_metadata()
extras = project["optional-dependencies"]

assert set(extras) >= {"observability", "secrets", "test"}
assert len(extras["observability"]) == 1
18 changes: 17 additions & 1 deletion uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading