chore(clients): roll out feed-level snapshot_status to all five clients

Task 1 added AlarmSnapshotStatus and AlarmFeedMessage.snapshot_status = 5.
Carry it downstream from the canonical Contracts protos:

- Rust vendored protos under clients/rust/protos, refreshed byte-identical
  (build.rs falls back to them for out-of-repo tarball builds)
- client descriptor set (protoc 34.1 pin)
- Go (protoc-gen-go v1.36.11 / protoc-gen-go-grpc 1.6.2)
- Python (grpcio-tools 1.80.0 pin)
- Java (gradle generateProto)

.NET needs no regeneration: the client compiles against the Contracts
Generated/ output committed with the proto change.

The hand-written CLI feed renderers switch on the payload oneof, so codegen
alone does not carry the arm. Add snapshot-status to the .NET, Go, Rust, and
Java renderers; the .NET and Go renderers were also missing provider-status,
which has been on the wire since the provider-mode work, so add it there too.
Java's renderer is an exhaustive switch expression and did not compile until
the new case landed. The Python CLI renders generic protobuf-JSON and needs
no change.

Each client README gains a paragraph on the feed-level frame next to its
existing from_truncated_snapshot paragraph: it arrives at stream open after
provider_status and before the cached active_alarm frames, then on every
verdict change including the clearing frame a monitor restart emits, so a
live consumer can track set completeness without polling QueryActiveAlarms.

GatewayDashboardDesign: list the two new payload cases the AlarmsHub forwards,
and — separately — record the GroupToRole / GroupToTag / UntaggedSessionVisibility
rows the settings page already renders but the bullet list omitted.
This commit is contained in:
Joseph Doherty
2026-08-18 05:26:06 -04:00
parent d13144a9d7
commit c7483615cf
15 changed files with 1412 additions and 408 deletions
+9
View File
@@ -132,6 +132,15 @@ poll. Treat the set as possibly incomplete rather than reconciling deletions
from it. It is set-level degraded status, not a comment on the record's own
fidelity, and is distinct from `degraded` (the subtag fallback provider).
`AlarmFeedStream` also carries that completeness verdict at feed level, as an
`alarm_feed_message::Payload::SnapshotStatus` frame whose `truncated` field is
true while the monitor's cached set derives from a truncated fetch. One arrives
at stream open (after the `ProviderStatus` frame, before the cached
`ActiveAlarm` frames) so a late joiner learns the current verdict, then one on
every verdict change — including the clearing frame sent when the gateway's
alarm monitor restarts and drops a truncated verdict. Track it if you need set
completeness on a live feed without polling `query_active_alarms`.
The session helpers keep MXAccess handles visible:
```rust
+9 -1
View File
@@ -2231,7 +2231,7 @@ fn event_value_to_json(value: &ProtoMxValue) -> Value {
}
/// Render a streamed [`AlarmFeedMessage`] as a terse one-line summary that
/// distinguishes the four `payload` oneof cases.
/// distinguishes the five `payload` oneof cases.
fn alarm_feed_message_summary(message: &AlarmFeedMessage) -> String {
match &message.payload {
Some(alarm_feed_message::Payload::ActiveAlarm(snapshot)) => {
@@ -2259,6 +2259,9 @@ fn alarm_feed_message_summary(message: &AlarmFeedMessage) -> String {
status.reason
)
}
Some(alarm_feed_message::Payload::SnapshotStatus(status)) => {
format!("snapshot-status truncated={}", status.truncated)
}
None => "(empty)".to_owned(),
}
}
@@ -2308,6 +2311,11 @@ fn alarm_feed_message_to_json(message: &AlarmFeedMessage) -> Value {
})),
}
}),
Some(alarm_feed_message::Payload::SnapshotStatus(status)) => json!({
"snapshotStatus": {
"truncated": status.truncated,
}
}),
None => Value::Null,
}
}
@@ -1018,6 +1018,10 @@ message AlarmFeedMessage {
// Provider-mode status. Emitted once on stream open and again on every
// failover/failback so late joiners learn the current mode immediately.
AlarmProviderStatus provider_status = 4;
// Snapshot-completeness status. Emitted once on stream open and again on
// every change of the truncation verdict, so late joiners learn whether the
// feed's active-alarm set may be incomplete.
AlarmSnapshotStatus snapshot_status = 5;
}
}
@@ -1028,6 +1032,23 @@ message AlarmProviderStatus {
google.protobuf.Timestamp since = 4;
}
// Feed-level snapshot-completeness status. Emitted once on StreamAlarms open
// (after the initial provider_status frame, before the cached active_alarm
// frames) so late joiners learn the current verdict, and again on every change
// of the truncation verdict — when a reconcile reports a different verdict, and
// when the gateway's alarm monitor restarts and drops a truncated verdict with
// the cache generation it described (feed subscribers outlive that monitor
// session, so they are sent the clearing frame). Mirrors the per-record
// ActiveAlarmSnapshot.from_truncated_snapshot caveat at feed level so live
// consumers can reason about completeness without polling QueryActiveAlarms.
message AlarmSnapshotStatus {
// True while the monitor's cached active-alarm set derives from a truncated
// (capped) worker fetch — the set may be missing alarms. Distinct from
// provider degradation (AlarmProviderStatus.degraded), which describes the
// fidelity of the records rather than the completeness of the set.
bool truncated = 1;
}
message MxStatusProxy {
// Mirrors the `success` member of the MXAccess MXSTATUS_PROXY struct
// (a 16-bit signed value in the COM struct, widened to int32 on the