M31 · gRPC engine: generated stubs, channel and auth - #54
Merged
Conversation
…ient The engine could have wrapped io.qdrant:client and been done in an afternoon. It generates its own stubs from Qdrant's .proto files instead, for two reasons that are both about what the module costs the people who use it. grpc-kotlin emits suspend functions and Flows, which is the shape QdrantTransport already has. Wrapping the official client would mean adapting ListenableFuture back into coroutines, which is the exact conversion the migration guide tells people not to write by hand. Generating also decides the dependency set rather than inheriting it. The engine resolves grpc-okhttp; the shaded Netty jar the official client carries is around nine megabytes on its own, most of what the README's footprint table charges to it. An opt-in gRPC engine that quietly costs what gRPC usually costs would have made the opt-in pointless. The protos are vendored verbatim at v1.18.2, the version the contract tests and the CI matrix already pin, so moving forward is a re-download and never a patch. qdrant.proto is left out: its only unique call returns the server's version, which no transport operation needs, and its imports drag in six internal cluster services to get it. Binary-compatibility validation ignores the generated packages. Their surface is Qdrant's to change, not ours to promise, and tracking it would bury the module's real API under thousands of generated lines. The transport itself is not here. What is here is the channel, the api-key metadata and a test that asserts what a real server received over the in-process transport, plus the proof that a REST-only build still resolves zero gRPC and zero protobuf.
This was referenced Jul 31, 2026
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.
First slice of #52. The foundation of
kdrant-transport-grpc, not the transport itself — see the scopenote at the bottom.
The decision this PR is really about
The engine generates its own stubs from Qdrant's
.protofiles rather than depending onio.qdrant:client. Two reasons, both about what the module costs its users:grpc-kotlinemitssuspendfunctions andFlows, which is the shapeQdrantTransportalreadyhas. Wrapping the official client would mean adapting
ListenableFutureback into coroutines — theexact conversion the migration guide tells people not to
write by hand.
grpc-okhttp; the shaded Netty jar the official client carries is around 9 MB on its own, most ofwhat the README's footprint table charges to it. An opt-in gRPC engine that quietly costs what gRPC
usually costs would make the opt-in pointless.
Verified
protobuf-gradle-plugin0.10.0 with protoc 4.35.1, grpc-java 1.83.1 and grpc-kotlin 1.5.0 produce 265 Kotlin and 12 Java
sources, including coroutine stubs for
Collections,Points,SnapshotsandHealth. The modulecompiles under
explicitApi().:kdrant-transport-rest:dependencies --configuration runtimeClasspathresolves zero gRPC or protobuf entries.server received, not the interceptor's own bookkeeping.
Choices worth reviewing
v1.18.2, the version the contract tests and the CI matrixalready pin. Refreshing is a re-download, never a patch — a vendored file that has been edited is one
nobody can diff against upstream.
qdrant.protois deliberately not vendored. Its only unique call returns the server's title,version and commit, which no
QdrantTransportoperation needs, and its imports pull in six internalcluster services to get it. The probes go through the standard
health_check.protoinstead.qdrant,grpc.health.v1). Theirsurface is Qdrant's to change, not ours to promise, and tracking it would bury the module's real API
under thousands of generated lines. The
.apifile is currently empty, which is correct: nothinghand-written is public yet.
protochad to be renamed toprotobuf-protocin the catalog. A library whose name is the prefix ofanother (
protoc-gen-grpc-java) becomes a namespace and stops being reachable as a leaf.Scope
No
QdrantTransportimplementation and no CHANGELOG entry. The seam has around 45 operations andthey are the bulk of M31's estimate; a partial implementation cannot compile without stubbing the rest
with
TODO(), and that is not something to merge intomain. Nothing user-facing has changed yet,which is why the changelog stays quiet until the transport lands.