Direct answer: identify the transport first, then apply the protocol

The HTTP analyzer is downstream of TLS plaintext capture. For known transport identity, it derives an opaque connection ID from the process, its start time, the TLS implementation, and the captured transport handle. It then pairs HTTP/1.1 requests with final responses in connection-local order, or matches HTTP/2 requests and responses by connection and stream ID. The event records say how each pair was constructed. This is protocol correlation, not proof that every byte of a request or response was observed.

This article reviews the public v1.0.35 source at c1574366122a90c451bca6a84713e28813ab95e2. It is a source-level explanation, not a new performance benchmark or a claim that every agent/runtime exposes usable TLS identities. For the broader decision about which observation plane to use, see eBPF monitoring boundaries.

What makes a connection identity stronger than a PID/TID?

For a capture that reports a nonzero transport_handle andprocess_start_ns together with a recognized tls_library, the parser resolves the tuple (pid, process_start_ns, tls_library, transport_handle) into an opaque, capture-local connection_id. The process start value distinguishes PID reuse; the TLS handle distinguishes connections used by the same process. Thread ID remains provenance: it may change between a request write and a response read and therefore should not be treated as the connection key.

A supported TLS close, ten-minute idle expiry, or bounded-state eviction retires this identity. Reusing a raw handle later receives another capture-local identity. A new opaque ID does not establish a new physical TCP connection, and missing lifecycle events still limit certainty. The analyzer does not persist raw TLS pointer addresses in SQLite or OTel call identity.

HTTP/1.1, HTTP/2, and legacy traces need different matching rules

Evidence pathHow exchange identity is assignedBoundary to remember
HTTP/1.1 with known TLS connectionRequests receive sequential exchange IDs; final responses consume that connection's pending-request FIFO.Informational 1xx responses do not consume the request; server-side capture uses the HTTP start line, not read/write direction, to classify messages.
HTTP/2 with known TLS connectionThe exchange key includes the connection and HTTP/2 stream ID; directional HPACK and CONTINUATION state stay connection-local.A response completes at END_STREAM. RST_STREAM and GOAWAY may end a stream with terminal evidence rather than a complete response.
Incomplete/unknown TLS identityLegacy HTTP/1 reassembly retains the older PID/TID-scoped path; matches are explicitly labeled inferred.This includes older traces and captures without supported identity, such as documented rustls paths. Inference is not the same as an exact connection match.

HTTP/1.1 handles declared Content-Length, chunked bodies and trailers, and close-delimited responses. HEAD, 204, and 304 do not require a body. Conflicting length declarations or malformed chunking are protocol errors, not permission to pair the next convenient response. The parser keeps request and response buffers separate for each connection and direction.

Read the correlation fields as evidence labels, not success badges

FieldInterpretationDo not infer
http_exchange_idShared request/response key constructed by this capture's analyzer.A provider request ID, globally stable ID, or independently verified application trace.
correlation_methodh1_connection_fifo, h2_stream, or a labeled legacy method.That different protocols or fallbacks have the same evidence strength.
correlation_statusexact for protocol matching with known identity; inferred for legacy evidence; unlinked for unmatched/terminated calls.That "exact" means lossless capture, validated model semantics, or complete body.
completion_reasonHow a message or pending exchange finished, including loss, timeout, close, reset, GOAWAY, eviction or capture end.That capture end implies a clean TLS close.
stream_id, correlation_versionHTTP/2 stream where applicable; version 2 for known identity, 1 for legacy correlation.That a null stream on HTTP/1.1 is an error.

The additional confidence value ranks a matching method inside this implementation; it is not a calibrated probability. Fragment provenance is also not traffic accounting: one TLS call can contribute bytes to more than one decoded HTTP message, so summing each message's provenance bytes can double-count transport volume.

A truncated request is not an absent request

Two independent budgets can cut an HTTP/1.1 message short. The TLS capture retains at most 256 KiB per SSL operation, and the HTTP/1 parser retains at most 1 MiB of message prefix. When a readable HTTP start line and prefix survive, the parser emits a partial HTTP event instead of dropping it. It sets body_truncated: true with a reason ofcapture_truncated or body_limit, and reportsbody_captured_bytes. When the peer declared Content-Length, the originalcontent_length can be compared with the retained prefix.

These fields make an important operational difference. A truncated body is not a complete JSON document or safe decompression input. If enough framing is known to skip precisely the lost Content-Length bytes, later HTTP/1.1 messages may still be matched. If framing cannot be resynchronized—for example, a cut chunked or close-delimited body—the analyzer stops pairing that connection until retirement. A similar truncation in HTTP/2 invalidates protocol state instead of trusting a damaged frame or HPACK dictionary.

What happens when collection loses data?

The ring-buffer loss counter applies to the tracer, not just one HTTP stream. A change in that counter, including a final CAPTURE_LOSS event, invalidates pending matches across active connections. The raw captured input remains available, but the analyzer emits terminal or unlinked evidence rather than guessing where the next byte belongs. Likewise, a known exchange ID without a pending request does not fall back to a different thread's request. Legacy events without explicit HTTP identity retain their separate fallback rules.

An unfinished exchange at end of input receives capture_end; this is not proof of TLS close. Source-level finalization requires a drained event stream, and abrupt cancellation cannot guarantee it. Partial terminal events withsource="http_correlation" are diagnostics, not normal HTTP responses.

SSE and OpenTelemetry preserve the boundary rather than repair it

For identified TLS transports, the analyzer runs HTTP parsing, decompression, and SSE processing before materialization. A complete SSE body can preserve HTTP exchange evidence when converted into an aggregate. This v1.0.35 stage does not promise early incremental SSE response chunks: long streaming responses may remain pending or unlinked until a terminal event. The source explicitly defers incremental streaming.

SQLite call rows store nullable connection, protocol, stream, exchange and evidence columns; legacy read-only databases synthesize nulls rather than retroactively re-correlating historical events. Where present, OTel exports add corresponding evidence attributes. That makes protocol matching complementary to application-level and OpenTelemetry tracing, not a replacement for application span context.

Bounded state changes what "no match" means

The parser bounds active connections to 1,024, HTTP/2 streams and pending header blocks to 1,024 per connection, header blocks to 64 KiB, HTTP/1 prefixes and HTTP/2 bodies to 1 MiB, and fragment provenance to 4,096 entries per direction. Pending HTTP/1 requests are capped at 1,024, and the materialized pending-exchange view holds at most 16,384 entries with a five-minute expiry. Reaching a limit produces terminal evidence instead of a fabricated successful request/response pair.

Other failure cases include capture beginning in the middle of a connection, TLS-library coverage gaps, unobserved close events, missed fragments, and parsing of plaintext that arrived out of protocol order. These are reasons to preserve the raw provenance and native agent trace where available; none turns absence of a reconstructed call into proof that no outbound request occurred.

How to investigate one suspicious match

Reproduce the workload on a Linux host with supported eBPF/TLS capture, retain the original saved database, and inspect the available reconstructed call evidence before attributing cost or latency to a specific provider request. The supported command entry point is shown below; consult the version-matched product README for platform and runtime setup. A saved run is sensitive and must not be uploaded unredacted merely to debug matching.

sudo agentsight record -- <agent-command>
# Then inspect the saved session with the supported report workflow:
agentsight report --db path/to/agentsight-run.db

For a source-level investigation, ask these questions in order: Does a record contain supported TLS identity? Is its correlation method connection FIFO, HTTP/2 stream, or legacy inference? Do the request and response share an exchange ID? Arecompletion_reason, body_truncated, and capture-loss counters consistent with the bytes actually retained? Does the native agent record supply a separate request timeline? This procedure is an interpretation checklist, not a claim that every field appears in the default human-readable report.

The implementation references below provide a reproducible source audit. The parser regression cases include same-connection requests using different TIDs and overlapping HTTP/1.1 exchanges—precisely where a PID/TID-only join can mislead. Also read why AI agent TLS traffic is difficult to capture before inferring that a missing payload was never sent.

Primary sources and reviewed scope

All product statements above are pinned to AgentSight v1.0.35 source commit c1574366122a90c451bca6a84713e28813ab95e2, released 23 October 2026. The analysis separates the documented parser contract from any unperformed production measurement. A valid future benchmark would need its own workload, runtime identity, TLS library, capture loss accounting, and ground-truth HTTP exchanges.

Next: read the local telemetry and data-handling limits, or compare the distinct GenAI span export path.