clients: document supervisory/array-write parity gotchas and add advise-supervisory to all CLIs

A consuming project hit two MXAccess parity surprises: a plain Write only
records its user_id when the item has an active supervisory advise (the path
to take when not authenticating), and array writes replace the whole array
rather than patching individual elements. Document both across the five client
READMEs and gateway.md's compatibility baseline, and expose the missing
advise-supervisory subcommand in the go/python/rust/java CLIs (plus the .NET
help text) so callers can establish the supervisory advise without dropping to
the raw command API.
This commit is contained in:
Joseph Doherty
2026-06-17 20:14:48 -04:00
parent bed647ca2c
commit 9eedf9d6a9
12 changed files with 416 additions and 4 deletions
@@ -153,6 +153,8 @@ public final class MxGatewayCli implements Callable<Integer> {
commandLine.addSubcommand("register", new RegisterCommand(clientFactory));
commandLine.addSubcommand("add-item", new AddItemCommand(clientFactory));
commandLine.addSubcommand("advise", new AdviseCommand(clientFactory));
commandLine.addSubcommand(
"advise-supervisory", new AdviseSupervisoryCommand(clientFactory));
commandLine.addSubcommand("subscribe-bulk", new SubscribeBulkCommand(clientFactory));
commandLine.addSubcommand("unsubscribe-bulk", new UnsubscribeBulkCommand(clientFactory));
commandLine.addSubcommand("read-bulk", new ReadBulkCommand(clientFactory));
@@ -1044,6 +1046,34 @@ public final class MxGatewayCli implements Callable<Integer> {
}
}
@Command(
name = "advise-supervisory",
description = "Invokes MXAccess AdviseSupervisory.")
static final class AdviseSupervisoryCommand extends GatewayCommand {
@Option(names = "--session-id", required = true, description = "Gateway session id.")
String sessionId;
@Option(names = "--server-handle", required = true, description = "MXAccess server handle.")
int serverHandle;
@Option(names = "--item-handle", required = true, description = "MXAccess item handle.")
int itemHandle;
AdviseSupervisoryCommand(MxGatewayCliClientFactory clientFactory) {
super(clientFactory);
}
@Override
public Integer call() {
try (MxGatewayCliClient client = clientFactory.connect(common.resolved())) {
MxCommandReply reply =
client.session(sessionId).adviseSupervisoryRaw(serverHandle, itemHandle);
writeOutput("advise-supervisory", common, json, reply, () -> reply.getKind().name());
}
return 0;
}
}
@Command(name = "subscribe-bulk", description = "Invokes MXAccess SubscribeBulk.")
static final class SubscribeBulkCommand extends GatewayCommand {
@Option(names = "--session-id", required = true, description = "Gateway session id.")
@@ -1830,6 +1860,8 @@ public final class MxGatewayCli implements Callable<Integer> {
MxCommandReply adviseRaw(int serverHandle, int itemHandle);
MxCommandReply adviseSupervisoryRaw(int serverHandle, int itemHandle);
MxCommandReply writeRaw(int serverHandle, int itemHandle, MxValue value, int userId);
List<SubscribeResult> subscribeBulk(int serverHandle, List<String> items);
@@ -1948,6 +1980,17 @@ public final class MxGatewayCli implements Callable<Integer> {
return session.adviseRaw(serverHandle, itemHandle);
}
@Override
public MxCommandReply adviseSupervisoryRaw(int serverHandle, int itemHandle) {
return session.invokeCommand(MxCommand.newBuilder()
.setKind(MxCommandKind.MX_COMMAND_KIND_ADVISE_SUPERVISORY)
.setAdviseSupervisory(
mxaccess_gateway.v1.MxaccessGateway.AdviseSupervisoryCommand.newBuilder()
.setServerHandle(serverHandle)
.setItemHandle(itemHandle))
.build());
}
@Override
public MxCommandReply writeRaw(int serverHandle, int itemHandle, MxValue value, int userId) {
return session.writeRaw(serverHandle, itemHandle, value, userId);
@@ -1302,6 +1302,15 @@ final class MxGatewayCliTests {
.build();
}
@Override
public MxCommandReply adviseSupervisoryRaw(int serverHandle, int itemHandle) {
adviseCalled = true;
return MxCommandReply.newBuilder()
.setKind(MxCommandKind.MX_COMMAND_KIND_ADVISE_SUPERVISORY)
.setProtocolStatus(ok())
.build();
}
@Override
public MxCommandReply writeRaw(int serverHandle, int itemHandle, MxValue value, int userId) {
lastWriteValue = value;