Skip to content

Surface the gRPC manifest via a ServiceCapabilities descriptor source (GH-3267)#3268

Merged
jeremydmiller merged 1 commit into
mainfrom
feat/grpc-capabilities-descriptor-source-3267
Jun 27, 2026
Merged

Surface the gRPC manifest via a ServiceCapabilities descriptor source (GH-3267)#3268
jeremydmiller merged 1 commit into
mainfrom
feat/grpc-capabilities-descriptor-source-3267

Conversation

@jeremydmiller

Copy link
Copy Markdown
Member

Closes #3267. Builds on #3266.

Summary

The gRPC endpoint manifest (IGrpcEndpointManifest, #3266) lived only inside Wolverine.Grpc and never reached the ServiceCapabilities capability path. A monitoring console (CritterWatch) therefore had no way to discover the gRPC services a Wolverine app exposes — the way it already discovers HTTP chains (IHttpGraphUsageSource) and ASP.NET endpoints (IAspNetEndpointDescriptorSource) via ServiceCapabilities.ReadFrom.

This PR adds the parallel descriptor/source plumbing for gRPC:

  • GrpcRpcDescriptor : OptionsDescription (Wolverine core, beside ServiceCapabilities) — one per RPC, carrying service name, method, RPC kind (GrpcRpcStreamKind), discovery mode, the published/request message type, response type, and the forwarding origin. Types are serializable TypeDescriptors; Subject is GrpcEndpoint[Service/Method] and each is tagged grpc.
  • IGrpcEndpointDescriptorSource — discovery source mirroring IAspNetEndpointDescriptorSource; registered in DI by Wolverine.Grpc, projecting the runtime IGrpcEndpointManifest into descriptors (lazy + cached).
  • ServiceCapabilities.GrpcEndpoints + readGrpcEndpoints — folds every registered source into the snapshot, ordered by service::method (mirrors AspNetEndpoints).

Design note — why Wolverine core, not JasperFx.Descriptors

The issue suggested putting the descriptor in JasperFx.Descriptors (mirroring AspNetEndpointDescriptor). But ServiceCapabilities is itself a Wolverine-core type and CritterWatch already references WolverineFx, so a core-resident descriptor is equally consumable — without a coordinated JasperFx release and a 2.16→2.18 pin bump. This keeps #3267 a single self-contained PR. Hand-written and direct-mapped services stay excluded (inherited from the manifest): they delegate to user code and have no message-publishing origin.

Test coverage

grpc_capabilities_descriptor_source_3267.cs — across every supported gRPC configuration, through both the raw IGrpcEndpointDescriptorSource and the end-to-end ServiceCapabilities.ReadFrom path:

Configuration Asserted
proto-first unary (SayHello) full mapping: service/method/kind/mode/request/response/origin/Subject/grpc tag
proto-first server-streaming (StreamGreetings) kind + request DTO + stream-element response
proto-first bidirectional (Echo, via BidiStreamingFixture) kind + per-item request element type
code-first unary (Greet) full mapping incl. contract-interface origin
code-first server-streaming (StreamGreetings) kind + IAsyncEnumerable<T> element response
invariants every descriptor has Subject/RequestType/Origin/grpc tag; capabilities ordered by service::method; only bus-forwarding modes surface
no gRPC GrpcEndpoints empty and no source registered

Local: Wolverine.Grpc.Tests 247/247 + the CoreTests capability/ReadFrom acceptance suite 24/24 (net9.0).

🤖 Generated with Claude Code

…iptor source (GH-3267)

The gRPC endpoint manifest (GH-3266) lived only inside Wolverine.Grpc and never
reached the ServiceCapabilities capability path, so a monitoring console
(CritterWatch) had no way to discover the gRPC services a Wolverine app exposes
the way it discovers HTTP chains (IHttpGraphUsageSource) and ASP.NET endpoints
(IAspNetEndpointDescriptorSource).

This adds the parallel descriptor/source plumbing for gRPC:

- GrpcRpcDescriptor : OptionsDescription (Wolverine core, next to ServiceCapabilities)
  carrying per-RPC service name, method, RPC kind, the published/request message
  type, response type, and the forwarding origin (all types as serializable
  TypeDescriptors).
- IGrpcEndpointDescriptorSource — discovery source mirroring
  IAspNetEndpointDescriptorSource; registered in DI by Wolverine.Grpc, projecting
  the runtime IGrpcEndpointManifest into descriptors.
- ServiceCapabilities.GrpcEndpoints + readGrpcEndpoints, folding every registered
  source into the snapshot ordered by service::method (mirrors AspNetEndpoints).

The descriptor lives in Wolverine core rather than JasperFx.Descriptors:
ServiceCapabilities is itself a Wolverine-core type and CritterWatch already
references WolverineFx, so a core-resident descriptor is equally consumable
without a coordinated JasperFx release. Hand-written and direct-mapped services
stay excluded (inherited from the manifest) — they delegate to user code and have
no message-publishing origin.

Adds coverage across every supported configuration: proto-first
unary/server-streaming/bidirectional and code-first unary/server-streaming
through both the raw source and the end-to-end ServiceCapabilities.ReadFrom path,
plus the no-gRPC (empty, no source registered) case.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@jeremydmiller jeremydmiller merged commit 7ca720e into main Jun 27, 2026
26 checks passed
This was referenced Jun 29, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Surface the gRPC endpoint manifest via a ServiceCapabilities descriptor source (for monitoring consoles)

1 participant