diff --git a/clients/rust/README.md b/clients/rust/README.md index cf2f0e1..bc72195 100644 --- a/clients/rust/README.md +++ b/clients/rust/README.md @@ -28,11 +28,13 @@ tarball, where the rest of the mxaccessgw repo does not exist. The vendored copies are shipped in the published `.crate` via `Cargo.toml`'s `include` list, which is what makes the crate buildable standalone; they are build inputs only, never a second source of truth. **Refresh rule:** any commit -that edits a Contracts proto (`mxaccess_gateway.proto`, `mxaccess_worker.proto`, -`galaxy_repository.proto`) must copy the changed file(s) into -`clients/rust/protos/` in that same commit — `scripts/check-codegen.ps1` -Check 3 fails the build on byte drift between the vendored copies and the -canonical Contracts protos. `tonic`/`prost` bindings are generated into +that edits *or adds* a Contracts proto (today `mxaccess_gateway.proto`, +`mxaccess_worker.proto`, `galaxy_repository.proto`) must copy the changed or +new file(s) into `clients/rust/protos/` in that same commit — +`scripts/check-codegen.ps1` Check 3 fails the build on byte drift between the +vendored copies and the canonical Contracts protos, and equally on a canonical +proto that has no vendored copy (which an in-repo build cannot catch, since +`build.rs` reads the canonical directory here). `tonic`/`prost` bindings are generated into Cargo build output. `src/generated.rs` declares the Rust modules that include those generated files. `src/generated` remains reserved for checked-in generator output if the crate later changes to source-tree generation. diff --git a/docs/ClientPackaging.md b/docs/ClientPackaging.md index 8833e72..419b5f9 100644 --- a/docs/ClientPackaging.md +++ b/docs/ClientPackaging.md @@ -206,7 +206,8 @@ publish` ship them inside the `.crate`, making the crate buildable standalone with no access to the rest of the mxaccessgw repo. Any Contracts proto change must refresh `clients/rust/protos/` in the same commit; `scripts/check-codegen.ps1` Check 3 byte-compares the vendored copies against the canonical protos and -fails on drift. Because the vendored protos make a standalone build possible, +fails on drift — in both directions, so a newly added canonical proto that +was never vendored fails there rather than at a consumer's standalone build. Because the vendored protos make a standalone build possible, `cargo package`/`cargo publish` run **with** verification (no `--no-verify`) — a `cargo package` that cannot build from the vendored tree alone would mean the vendored copies are stale, and verification is what catches that before diff --git a/docs/GatewayTesting.md b/docs/GatewayTesting.md index 8679b12..d87cd63 100644 --- a/docs/GatewayTesting.md +++ b/docs/GatewayTesting.md @@ -689,6 +689,11 @@ committed client descriptor set (Check 1), the C# `Generated/` (Check 2), the Ru protos (Check 3), or the Go/Python client bindings (Check 4, IPC-25) no longer match the current `.proto` sources — the codegen drift class this repo has hit repeatedly (stale client descriptors, net48 `CS0246` on unregenerated protos, silently stale Go/Python worker bindings). +Check 3 sweeps both directions: a vendored copy that drifted from (or has no) canonical proto +fails, and so does a canonical proto with no vendored copy at all. The second direction matters +because `clients/rust/build.rs` prefers the canonical directory whenever it exists, so an +unvendored proto builds fine in-repo and only breaks the standalone crate build a consumer runs +from the published tarball — drift no in-repo build can surface. Check 4 regenerates the Go and Python bindings with their pinned generators (`protoc-gen-go` v1.36.11 / `protoc-gen-go-grpc` 1.6.2, `grpcio-tools` 1.80.0) and fails on any diff; a missing generator fails the check rather than skipping it. The **primary** guard for the diff --git a/scripts/check-codegen.ps1 b/scripts/check-codegen.ps1 index ab19901..a7b7038 100644 --- a/scripts/check-codegen.ps1 +++ b/scripts/check-codegen.ps1 @@ -11,8 +11,11 @@ # (which breaks the net48 worker build with CS0246 — see docs/Contracts.md). # 3. The Rust crate's vendored protos (clients/rust/protos/*.proto — build inputs that make the # crate buildable outside the repo, CLI-02) are byte-identical to the canonical Contracts -# protos. A drift means a .proto was edited without refreshing the vendored copies, which would -# publish a stale wire contract to crate consumers while the in-repo build stays correct. +# protos, and the two directories hold the same set of files. A drift means a .proto was edited +# without refreshing the vendored copies, which would publish a stale wire contract to crate +# consumers while the in-repo build stays correct. The sweep runs both directions: a canonical +# proto with no vendored copy is just as broken (the published crate cannot build standalone), +# and it is invisible in-repo because build.rs prefers the canonical directory when it exists. # 4. The committed Go and Python client bindings match a fresh regeneration (IPC-25). The two # per-client generate-proto.ps1 scripts pin their generators (protoc-gen-go v1.36.11 / # protoc-gen-go-grpc v1.6.2 for Go; grpcio-tools 1.80.0 for Python), so a clean checkout @@ -88,6 +91,16 @@ try { $failures.Add("Rust vendored proto drifted from canonical: clients/rust/protos/$($vendored.Name). Refresh it from src/ZB.MOM.WW.MxGateway.Contracts/Protos/$($vendored.Name).") } } + + # Reverse direction: a canonical proto that was never vendored passes the loop above (it only + # walks the vendored dir) but breaks a standalone crate build, because build.rs falls back to + # clients/rust/protos/ only outside the repo — in-repo it reads the canonical dir and stays green. + foreach ($canonicalProto in Get-ChildItem -Path $canonicalProtoDir -Filter '*.proto' -File) { + $vendoredCounterpart = Join-Path $vendoredProtoDir $canonicalProto.Name + if (-not (Test-Path $vendoredCounterpart)) { + $failures.Add("Canonical proto is not vendored for the Rust crate: $($canonicalProto.Name). Copy src/ZB.MOM.WW.MxGateway.Contracts/Protos/$($canonicalProto.Name) to clients/rust/protos/$($canonicalProto.Name) (and add it to build.rs's input list).") + } + } } catch { $failures.Add("Rust vendored proto check failed: $($_.Exception.Message)")