feat(mqtt): vendor Tahu sparkplug_b.proto + Grpc.Tools codegen

Vendors the NORMATIVE (proto2) Eclipse Tahu sparkplug_b.proto and compiles it
in .Contracts with build-time Grpc.Tools, message-only (GrpcServices="None") --
Sparkplug rides MQTT, there is no gRPC service, so no Grpc.Core.Api is pulled in.

Provenance rides in the file header: repo, path, pinned commit
5736e404889d4b95910613040a99ba79589ffb13, permalink, git blob SHA-1
bf72ab5f..., content SHA-256 4432c5c4..., EPL-2.0, and a re-verify recipe. The
body below line 38 is byte-for-byte upstream; the blob SHA-1 matches the tree
entry at that commit, so the copy is provably genuine and not reconstructed.

Chose the proto2 file over upstream's sibling sparkplug_b_c_sharp.proto: the
sibling is a lossy proto3 restatement that drops explicit presence, and protoc
generates valid C# from proto2 into the identical namespace
(Org.Eclipse.Tahu.Protobuf, PascalCased from the package -- no
csharp_namespace option). Presence matters downstream: an NBIRTH legitimately
carries seq = 0 and a DATA metric legitimately omits `name`, so Has{Seq,Name,
Alias,IsNull,Datatype} is the difference between "absent" and "present, zero".

.Contracts stays transport-free: Google.Protobuf is a serialization dependency
with a framework-only graph, Grpc.Tools is PrivateAssets=all, and the resolved
graph is exactly {Google.Protobuf, Grpc.Tools, Core.Abstractions} -- no MQTTnet.

Codegen tests pin the round-trip, the namespace, the Sparkplug field numbers,
the DataType spec indices, and protoc's enum-name mangling (UInt64 -> Uint64,
UUID -> Uuid) that Task 17's datatype map has to spell correctly.

Claude-Session: https://claude.ai/code/session_01GASWkNEi68FSCtvr6rLoEW
This commit is contained in:
Joseph Doherty
2026-07-24 20:54:23 -04:00
parent 92ba120964
commit 1ae26675ac
3 changed files with 386 additions and 0 deletions
@@ -8,4 +8,29 @@
<ItemGroup>
<ProjectReference Include="..\..\Core\ZB.MOM.WW.OtOpcUa.Core.Abstractions\ZB.MOM.WW.OtOpcUa.Core.Abstractions.csproj"/>
</ItemGroup>
<!-- Sparkplug B (P2): the vendored Eclipse Tahu schema is compiled here, in the one assembly all
four MQTT projects reference. Message-only codegen (GrpcServices="None") — Sparkplug rides MQTT,
there is no gRPC service, so no Grpc.Core.Api runtime reference is needed (Commons, this repo's
other locally-compiled proto, takes one only because it generates service stubs).
Google.Protobuf is a SERIALIZATION dependency, not a transport one, so .Contracts stays
transport-free: it still has no MQTTnet reference (dropped in Task 1) and Google.Protobuf's own
graph is framework-only. Grpc.Tools is build-time (PrivateAssets=all) and flows to no consumer.
Build-platform note (inherited, not new): Grpc.Tools' bundled linux_arm64 protoc segfaults
(exit 139) under Apple-Silicon Docker, which is why docker-dev/Dockerfile pins its build stage
to --platform=linux/amd64. That pin already exists for the Commons proto; this project adds a
second .proto to the same already-pinned build, not a new constraint. -->
<ItemGroup>
<PackageReference Include="Google.Protobuf"/>
<PackageReference Include="Grpc.Tools">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>
<Protobuf Include="Protos\sparkplug_b.proto" GrpcServices="None"/>
</ItemGroup>
</Project>