ABP Compatibility Contract¶
This page freezes the observable behavior preserved while the Autobench Instrumentation Protocol (ABP) replaces legacy span and instrumentation internals. Phases 1 through 8 now satisfy this contract. The complete public instrumentation guide is in Instrumentation And Traces.
Compatibility Boundary¶
The following top-level imports remain available while ABP is introduced:
from autobench import (
ArtifactRef,
AssetVersion,
DurationMetricSpec,
ErrorRecord,
InstrumentationHandle,
InstrumentCall,
InstrumentFactorSpec,
InstrumentMetricSpec,
Observation,
RunContext,
RunRecord,
Span,
SpanKind,
SpanRecord,
TraceEnvelope,
attach_trace,
get_active_run_context,
instrument_method,
trace_to_observations,
)
ABP may move implementations into new packages, but these imports and their current behavior remain compatibility facades until a separately announced deprecation cycle.
Manual spans¶
Existing manual spans preserve these guarantees:
ctx.span(...)is a synchronous context manager;- nested spans receive the active span as
parent_id; - every completed span has UTC start/end timestamps and a non-negative monotonic duration;
- a configured duration metric is linked to the span;
- metrics, factors, events, errors, and artifacts retain their span link;
- exceptions are recorded and then propagated;
Span.set_output,Span.set_attribute, andSpan.set_usagecontinue to update the recorded span;- entering instrumentation without an active run context remains a no-op;
- closing the final
InstrumentationHandlerestores the original descriptor.
The tests in tests/test_abp_compatibility.py are the executable form of this
contract.
Stored evidence¶
Legacy model-shaped RunRecord and TraceEnvelope YAML remains loadable. ABP
will add protocol data additively and preserve the existing spans input
during migration. Replay must not require the task module or an optional
instrumented SDK.
The frozen legacy examples are:
tests/fixtures/abp/legacy_run_record.yamltests/fixtures/abp/legacy_trace_envelope.yaml
Concurrency Regression Contract¶
RunContext now uses task-local ABP context. The concurrency migration is
covered by passing regression tests for all of these cases:
- concurrent sibling spans under one parent both point to that parent;
- a nested task inherits the parent active at task creation;
- completing one sibling does not change the other sibling's active parent;
- out-of-order completion does not corrupt later parent selection;
- cancellation closes only the cancelled branch and restores its context;
- separate RunContexts never share active spans.
The old mutable-stack reproduction is retained only in design history; it is not the current runtime behavior.
Canonical Trace Decision¶
ABP will have one canonical immutable Trace model. TraceEnvelope does not
have behavior that justifies a second trace representation, so it will become
a compatibility name for Trace rather than a parallel model. Existing
TraceEnvelope(...), attach_trace(...), and trace_to_observations(...)
callers continue to work.
This avoids conversion drift between manually attached traces and traces materialized from native ABP signals.
Package Shape¶
ABP code is introduced only when its phase needs it. Empty placeholder modules are not created.
autobench/
protocol/
ids.py
values.py
signals.py
traces.py
context.py
capture.py
collector.py
instrumentation/
models.py
manager.py
patching.py
streaming.py
pydantic_ai.py
openai.py
openai_agents.py
httpx.py
Small modules are combined when separation would only create navigation cost. Existing unrelated modules are not moved as part of ABP.
Optional Integration Targets¶
The initial integration extras are reserved as follows:
| Extra | Research baseline | First implementation phase |
|---|---|---|
autobench[pydantic-ai] |
Pydantic AI 2.22.0 | 10 |
autobench[openai] |
OpenAI Python 2.52.0 | 11 |
autobench[openai-agents] |
OpenAI Agents 0.19.2 | 11 |
autobench[httpx] |
HTTPX 0.28.1 | 12 |
autobench[instrumentation] |
all integrations above | 13 |
These versions are the public-API research baseline captured on 2026-08-03, not a compatibility claim. Dependency metadata is added only when each native instrumentor and its version matrix exist. Autobench core remains free of these dependencies.
Manual Span Performance Baseline¶
The baseline measures a minimal completed manual span with no observations,
artifacts, or errors. Each repeat creates one RunContext and records 10,000
spans. Timing uses timeit.repeat; duration comes from the host monotonic
clock. The benchmark does not enforce a CI latency threshold because shared CI
timing is not stable.
Reproduce it with:
uv run python scripts/benchmark_spans.py --iterations 10000 --repeats 7
Baseline captured before ABP runtime changes:
| Field | Value |
|---|---|
| Date | 2026-08-03 |
| Python | 3.11.13 |
| Platform | macOS 26.1 arm64 |
| Minimum | 3,227.4 ns/span |
| Median | 3,324.8 ns/span |
The raw per-repeat values were 3467.0, 3308.4, 3299.3, 3394.4,
3394.3, 3324.8, and 3227.4 ns/span. Later phases compare using the same
script and workload; they do not compare unrelated machine results.
Release measurements captured after ABP materialization on the same host:
| Workload | Measurement |
|---|---|
| Manual ABP span | 28,836.7 ns/span median |
| HTTPX baseline request | 35,346.2 ns/request median |
| Instrumented HTTPX request | 224,263.6 ns/request median |
| HTTPX instrumentation overhead | 188,917.4 ns/request median |
| 10,000 x 32-byte HTTP stream | 2,618.0 ns/chunk median |
| Long-stream peak allocation | 30,918 bytes |
The long-stream result is about 3.1 peak allocated bytes per emitted chunk, which confirms the
instrumentor does not retain chunk payloads as the stream grows. These numbers characterize this
machine and are not release thresholds. Reproduce transport and stream measurements with:
uv run python scripts/benchmark_spans.py --httpx --iterations 1000 --repeats 7
uv run python scripts/benchmark_spans.py --httpx-stream --chunks 10000 --chunk-size 32 --repeats 7