Repository navigation
feat: the agent names itself in the request it makes (ADR 0083) - #124
Merged
Merged
Conversation
Every request now carries `User-Agent: runtime-agent/<version>`.
The agent stated its version in one place: inside `collection_coverage`, as
a field about the sender riding in a document about the cluster. So the
answer arrived on that payload's cadence — between two coverage flushes the
question had none — and only a reader that already parses payloads could
get it. An access log, a proxy, a packet capture saw a sender that would
not say what it was.
A version is not a fact about the cluster. It describes what software made
the request, which is what User-Agent has always answered.
A version that cannot be stated is not stated. The build stamps it from
`git describe`, so its content comes from a tag, and a tag is a string this
repository does not control: bounded here at 64 characters of what a
semantic version is made of. Outside that the product travels alone,
naming the agent and claiming nothing about which build it is — a tag
holding a space or a slash is not a version in the shape the header agreed
to, and one holding a CRLF is not a version at all but a second header.
Nothing new leaves the cluster: `collection_coverage.agent.version` already
carried this exact string, from the same variable. The field stays, and
deliberately — the local sink writes byte-identical payloads to what the
backend sink transmits (invariant 2), and a header is not part of a
payload, so moving the version out of the body would hide it from everyone
reading a local sink.
go test ./... pass
golangci-lint (pinned v2.11.4) 0 issues
the wire is asserted, not the value: a test server records the header
of every request a round makes
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KeZECJXTDHL6Nts95eKMJA
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Every request now carries
User-Agent: runtime-agent/<version>.Why the request rather than a payload
The agent stated its version in exactly one place: inside
collection_coverage, asagent.version— a field about the sender riding in a document about the cluster. Three things follow from that, and none is about convenience:A version is not a fact about the cluster. It describes what software made the request, which is the question
User-Agenthas always answered.A standard header rather than an
X-one: anX-name is likelier to be dropped by an intermediary, and it is one more name for an operator to learn before they can read their own traffic.A version that cannot be stated is not stated
The build stamps the version from
git describe, so its content comes from a tag, and a tag is a string this repository does not control. What may be stated is bounded here — at most 64 characters of what a semantic version is made of, plus the letters that spell thedevan unstamped build carries.Outside that the product travels alone,
runtime-agent, naming the agent and claiming nothing about which build it is:1.4.2runtime-agent/1.4.2devruntime-agent/devv1.4.2-3-gb3691ed-dirtyruntime-agent/v1.4.2-3-gb3691ed-dirty1.4.2+build.5runtime-agent/1.4.2+build.5release/1.4runtime-agent1.4.2\r\nX-Scope: acmeruntime-agentSending the value anyway is worse than it looks. A tag holding a space or a
/produces something that is not a version in the shape the header agreed to; a tag holding a CRLF does not produce a bad version but a second header. Bounding it at the source means no reader has to be the one that notices.Half an answer is the right answer here, because a missing version is a case any reader must already handle: an agent built before this header existed sends none, and an intermediary may strip one that was sent.
Nothing new leaves the cluster
collection_coverage.agent.versionalready carried this exact string, from the same variable. What changes is the channel, not the data — which is whysecurity.mdgains a pointer rather than a promise.The payload keeps its field, and deliberately. The
localsink writes byte-identical payloads to what the backend sink transmits (CLAUDE.md invariant 2), and a header is not part of a payload. Moving the version out of the body would make it invisible to everyone reading a local sink — the configuration where no request is made at all.Verification
The wire is asserted, not the computed value: a test server records the
User-Agentof every request a shipping round makes, and every one must carry it. The table above is a second test overuserAgentdirectly, including the CRLF case.🤖 Generated with Claude Code
https://claude.ai/code/session_01KeZECJXTDHL6Nts95eKMJA