code-reviews: 2026-06-18 re-review of array-write-ergonomics feature at 88915c3
Re-reviewed the 10 modules touched by the MxSparseArray / array-write ergonomics work (8df5ab3..88915c3). 16 new findings: - Server-057 (Medium): [] AddItem normalization skips AddItemBulk/AddBufferedItem - Client.Dotnet-030 (Medium): advise-supervisory missing from IsKnownGatewayCommand (dead command) - 14 Low: MxSparseArray doc/test gaps, advise-supervisory CLI gaps across clients, Client.Java-049 / Client.Python-037 version-bump consistency misses Worker.Tests and IntegrationTests clean. Worker unchanged by the feature, not re-reviewed.
This commit is contained in:
@@ -4,10 +4,10 @@
|
||||
|---|---|
|
||||
| Module | `clients/java` |
|
||||
| Reviewer | Claude Code |
|
||||
| Review date | 2026-06-16 |
|
||||
| Commit reviewed | `8df5ab3` |
|
||||
| Review date | 2026-06-18 |
|
||||
| Commit reviewed | `88915c3` |
|
||||
| Status | Re-reviewed |
|
||||
| Open findings | 0 |
|
||||
| Open findings | 3 |
|
||||
|
||||
## Checklist coverage
|
||||
|
||||
@@ -123,6 +123,31 @@ Re-review of the Java client delta: the §8 `GalaxyClientFactory` seam, `InProce
|
||||
| 9 | Testing coverage | Client.Java-045, Client.Java-046 |
|
||||
| 10 | Documentation & comments | Client.Java-047, Client.Java-048 |
|
||||
|
||||
### 2026-06-18 review (commit 88915c3)
|
||||
|
||||
Re-review pass at `88915c3`. Diff against `8df5ab3` is six commits touching
|
||||
`clients/java`: `8df0479` / `bdb7e14` / `8cebe43` / `bed647c` (Client.Java-040..048
|
||||
fixes — control-character JSON escaping, stream-alarms terminal-slot fix, async
|
||||
overflow flood test, `InProcessGatewayHarness` Javadoc, Javadoc corrections,
|
||||
and `MxGatewayClientVersion` bump to 0.1.1); `9eedf9d` (parity-gotchas docs +
|
||||
`advise-supervisory` CLI subcommand across all language clients);
|
||||
`e7b8aa6` (Java `writeArrayElements` default-fill SDK helper + session test);
|
||||
`88915c3` (version bump `0.1.1 → 0.1.2` in `build.gradle`). Generated protobuf
|
||||
Java (`src/main/generated/`) excluded from review — build churn only.
|
||||
|
||||
| # | Category | Result |
|
||||
|---|---|---|
|
||||
| 1 | Correctness & logic bugs | No issues found. `writeArrayElements` builds the `MxSparseArray` correctly: `elementDataType`, `totalLength`, and elements iterated via `TreeMap` for deterministic ascending order match the Go/Rust/Python/dotnet reference implementations. The `MxValues.decode` `SPARSE_ARRAY_VALUE -> null` arm is sound — the type is write-only and never returned by the gateway; returning `null` is the correct sentinel (matches `KIND_NOT_SET`). |
|
||||
| 2 | mxaccessgw conventions | No issues found. `advise-supervisory` routes through `invokeCommand` using `MX_COMMAND_KIND_ADVISE_SUPERVISORY` — no MXAccess COM touched in the client, generated code untouched. |
|
||||
| 3 | Concurrency & thread safety | No issues found. The `stream-alarms` terminal-slot rework (`AtomicBoolean terminated` + `AtomicReference<Object> terminal`) is a sound first-terminal-wins design. The poll-then-check-terminal drain loop is correct for the `terminal.set` publish ordering (`terminated=true` is set before `terminal.set(item)`, but the drain only reads `terminal` when `poll` returns null, so a retry on the next 50ms poll sees it). |
|
||||
| 4 | Error handling & resilience | No issues found. `writeArrayElements` propagates transport/protocol errors via the existing `writeRaw` / `invokeCommand` path and its `MxGatewayException` contract. |
|
||||
| 5 | Security | No issues found. No new auth surface, no logging of values or credentials. |
|
||||
| 6 | Performance & resource management | No issues found. `new TreeMap<>(elements)` makes a defensive copy for deterministic iteration — correct and cheap for practical element counts. |
|
||||
| 7 | Design-document adherence | No issues found. `writeArrayElements` delegates to `writeRaw`, which ultimately routes through the normal `MX_COMMAND_KIND_WRITE` path — MXAccess parity is preserved; the gateway expands the sparse descriptor, not the client. |
|
||||
| 8 | Code organization & conventions | Issue found: `build.gradle` bumped to `0.1.2` but `MxGatewayClientVersion.CLIENT_VERSION` remains `"0.1.1"` and the tests assert `0.1.1` — same version-split as resolved Client.Java-044 (Client.Java-049). |
|
||||
| 9 | Testing coverage | Issue found: the new `advise-supervisory` CLI subcommand has a `FakeSession` stub but no dedicated CLI-level test (Client.Java-050). |
|
||||
| 10 | Documentation & comments | Issue found: `writeArrayElements` Javadoc documents `[0, totalLength)` index contract and `totalLength > 0` as required, but no client-side `IllegalArgumentException` is thrown for violations — only the Javadoc describes the constraint; Java `int` silently sign-extends to a large `uint32` on the wire for negative inputs (Client.Java-051). README dependency example still shows `0.1.1` (cross-ref Client.Java-049). |
|
||||
|
||||
## Findings
|
||||
|
||||
### Client.Java-001
|
||||
@@ -896,3 +921,57 @@ BrowseChildrenReply reply = galaxy.browseChildren(
|
||||
**Recommendation:** Add a `PROVIDER_STATUS` arm to `formatAlarmFeedMessage` that renders the provider status (mode / degraded / reason) consistently with the other alarm-feed arms — do not add a `default ->` that silently drops it, since the provider status is meaningful and the exhaustive switch is the compiler-enforced guard that catches exactly this kind of future contract drift.
|
||||
|
||||
**Resolution:** 2026-06-15 — Confirmed via `gradle :zb-mom-ww-mxgateway-cli:compileJava` failing with "the switch expression does not cover all possible input values" at `MxGatewayCli.java:1699` on the Windows host. Added a `case PROVIDER_STATUS ->` arm to `formatAlarmFeedMessage` yielding `provider-status mode=%s degraded=%b reason=%s` (from `AlarmProviderStatus.getMode().name()` / `getDegraded()` / `getReason()`), plus the `import mxaccess_gateway.v1.MxaccessGateway.AlarmProviderStatus;`. No `default` arm — the exhaustive switch expression remains the compile-time guard against future `payload` oneof additions. Verified `gradle test` builds and passes on the Windows host (Java 21).
|
||||
|
||||
### Client.Java-049
|
||||
|
||||
| Field | Value |
|
||||
|---|---|
|
||||
| Severity | Low |
|
||||
| Category | Code organization & conventions |
|
||||
| Location | `clients/java/build.gradle:16`, `clients/java/zb-mom-ww-mxgateway-client/src/main/java/com/zb/mom/ww/mxgateway/client/MxGatewayClientVersion.java:12`, `clients/java/zb-mom-ww-mxgateway-cli/src/test/java/com/zb/mom/ww/mxgateway/cli/MxGatewayCliTests.java:59,89`, `clients/java/README.md:399` |
|
||||
| Status | Open |
|
||||
|
||||
**Description:** Commit `88915c3` (`chore(clients): bump all five clients 0.1.1 -> 0.1.2`) incremented `build.gradle` `version = '0.1.2'` but left `MxGatewayClientVersion.CLIENT_VERSION = "0.1.1"` unchanged. The two CLI test assertions that check the version string also still assert `0.1.1` (lines 59 and 89 of `MxGatewayCliTests.java`), and the `README.md` Maven dependency example at line 399 shows `:0.1.1`. The published Gradle artifact carries version `0.1.2` (from `build.gradle`) while the `version` CLI command reports `mxgateway-java 0.1.1` and the README tells a consumer to depend on `:0.1.1`. Same class of version drift as the resolved Client.Java-044 (where `0.1.0` vs `0.1.1` was the split) — the fix for Client.Java-044 bumped `CLIENT_VERSION` to `"0.1.1"` but the `build.gradle` bump to `0.1.2` was not accompanied by a matching `MxGatewayClientVersion` update.
|
||||
|
||||
**Recommendation:** Bump `CLIENT_VERSION` to `"0.1.2"` in `MxGatewayClientVersion.java`, update the two `MxGatewayCliTests` assertions from `0.1.1` to `0.1.2`, and update the `README.md` dependency example coordinate to `:0.1.2`. Consider sourcing `CLIENT_VERSION` from a Gradle-generated resource file (e.g. via `processResources` task writing `version.properties`) so the two version strings cannot drift again.
|
||||
|
||||
### Client.Java-050
|
||||
|
||||
| Field | Value |
|
||||
|---|---|
|
||||
| Severity | Low |
|
||||
| Category | Testing coverage |
|
||||
| Location | `clients/java/zb-mom-ww-mxgateway-cli/src/main/java/com/zb/mom/ww/mxgateway/cli/MxGatewayCli.java:1046-1068` (new `AdviseSupervisoryCommand`), `clients/java/zb-mom-ww-mxgateway-cli/src/test/java/com/zb/mom/ww/mxgateway/cli/MxGatewayCliTests.java:1306-1313` (stub) |
|
||||
| Status | Open |
|
||||
|
||||
**Description:** Commit `9eedf9d` added the `advise-supervisory` CLI subcommand (`AdviseSupervisoryCommand`) to all language client CLIs. The Java `FakeSession.adviseSupervisoryRaw` stub was added to `MxGatewayCliTests` but no test exercises the new subcommand path. There is no test that calls `execute(factory, "advise-supervisory", "--session-id", "s", "--server-handle", "1", "--item-handle", "2")` and asserts the command routes through `session.adviseSupervisoryRaw`, produces a non-zero exit code on failure, or emits the correct JSON / text output. The `adviseCalled` field shared with `adviseRaw` means even an indirect smoke path that calls `advise` could mask a missing `adviseSupervisory` wire. Every other new CLI subcommand in this diff has a dedicated CLI-level test (the `writeArrayElements` helper has a session-level test in `MxGatewayClientSessionTests`).
|
||||
|
||||
**Recommendation:** Add a `@Test void adviseSupervisoryCommandCallsAdviseSupervisoryRaw()` to `MxGatewayCliTests` that exercises the subcommand via `execute(factory, "advise-supervisory", "--session-id", "s", "--server-handle", "12", "--item-handle", "34")` and asserts exit code 0, that `factory.client.session.adviseCalled` (or a dedicated `adviseSupervisoryCalled` boolean) is true, and that the output contains the reply kind string `MX_COMMAND_KIND_ADVISE_SUPERVISORY`. Consider renaming `adviseCalled` to `adviseSupervisoryCalled` for the `adviseSupervisoryRaw` stub (a separate `adviseCalled` for `adviseRaw`) to prevent future tests from masking each other.
|
||||
|
||||
### Client.Java-051
|
||||
|
||||
| Field | Value |
|
||||
|---|---|
|
||||
| Severity | Low |
|
||||
| Category | Documentation & comments |
|
||||
| Location | `clients/java/zb-mom-ww-mxgateway-client/src/main/java/com/zb/mom/ww/mxgateway/client/MxGatewaySession.java:622-657` |
|
||||
| Status | Open |
|
||||
|
||||
**Description:** `writeArrayElements` accepts `int totalLength` and `Map<Integer, MxValue> elements` whose keys are plain Java `int`. The proto fields `MxSparseArray.total_length` and `MxSparseElement.index` are both `uint32`. Java's protobuf runtime maps `uint32` to `int` (Java has no unsigned primitive), so passing a negative value to `setTotalLength(int)` or `setIndex(int)` silently sets the wire field to the two's-complement reinterpretation (e.g. `-1` → `4294967295`). The gateway will likely reject the resulting request with `INVALID_ARGUMENT`, but the error message will reference a large `uint32` value rather than the caller's negative `int`, making the failure hard to diagnose. The Javadoc states "supplied indices must be within `[0, totalLength)`" and "`totalLength` is required" but does not state what happens with negative inputs, and no `IllegalArgumentException` is thrown. All other language clients use unsigned types (`uint`, `uint32`, `u32`) that prevent negatives at the type level; Java cannot replicate that, so explicit validation is the correct substitute. The Python client is similarly unvalidated and its docstring explicitly defers to the gateway for rejection — but Python's `grpc` runtime raises an internal exception on negative `uint32` fields before the network call, so it fails more obviously than Java's silent wire wrap.
|
||||
|
||||
**Recommendation:** Add client-side guards before the `MxSparseArray.Builder` population:
|
||||
|
||||
```java
|
||||
if (totalLength <= 0) {
|
||||
throw new IllegalArgumentException("totalLength must be > 0, got " + totalLength);
|
||||
}
|
||||
for (Map.Entry<Integer, MxValue> entry : elements.entrySet()) {
|
||||
int idx = entry.getKey();
|
||||
if (idx < 0 || idx >= totalLength) {
|
||||
throw new IllegalArgumentException(
|
||||
"element index " + idx + " is out of range [0, " + totalLength + ")");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Add a test in `MxGatewayClientSessionTests` asserting both `IllegalArgumentException` paths (negative `totalLength`, negative/out-of-range index). Duplicate-index detection can be left to the gateway (the proto `repeated` field allows duplicates, and the gateway can sort out semantics).
|
||||
|
||||
Reference in New Issue
Block a user