fix(clients): render ReplayGap as the typed cross-CLI row in the .NET and Java CLIs (NEXT-02)
The .NET and Java stream-events commands handed the raw ReplayGap sentinel
MxEvent to their protobuf JSON formatters (Java text mode printed
'0 MX_EVENT_FAMILY_UNSPECIFIED'), while the Go/Python/Rust CLIs already emit
the typed row (CLI-35/36). Both now branch on the sentinel: Java text mode
prints 'REPLAY_GAP requested_after=<n> oldest_available=<n>' and JSON mode a
hand-built {"replayGap":{...}} line via nextItem()/isReplayGap(); the .NET
CLI emits the same hand-built row in jsonl/text (its text mode is
JSON-per-line) and inside the --json events array. Rows are hand-built so
the cursors are JSON numbers like the other three CLIs, not the proto3 JSON
mapping's quoted uint64 strings — the CrossLanguageSmokeMatrix divergence
table collapses to a single converged contract.
Tests: .NET MxGatewayClientCliTests 35/35 (new RendersReplayGapAsTypedRow
covers jsonl + aggregate); Java gradle test 52/52 (new
streamEventsRendersReplayGapAsTypedRow covers --json + text over the
in-process harness). No generated-file churn.
This commit is contained in:
@@ -40,27 +40,24 @@ reports the next deliverable sequence rather than `0` (see [Sessions](Sessions.m
|
||||
The default smoke sequence opens a fresh stream (no cursor) and does not exercise
|
||||
the gap path; a resume-with-gap fixture case is tracked separately (TST-24).
|
||||
|
||||
The CLIs differ in how they *print* that library-level signal. Three of them consume
|
||||
the typed gap and emit a dedicated row rather than a degenerate event row; the other
|
||||
two hand the raw sentinel `MxEvent` straight to the formatter, so they print the
|
||||
sentinel itself, whose `replayGap` field carries the same cursors:
|
||||
All five CLIs consume the typed gap and emit a dedicated row rather than a
|
||||
degenerate event row (the .NET and Java halves were the last to convert — NEXT-02):
|
||||
|
||||
| CLI | Text mode | JSON mode |
|
||||
|-----|-----------|-----------|
|
||||
| `mxgw-rs` (Rust, canonical) | `REPLAY_GAP requested_after=<n> oldest_available=<n>` | `{"replayGap": {"requestedAfterSequence": <n>, "oldestAvailableSequence": <n>}}` as one entry of the `events` array |
|
||||
| `mxgw-go` (Go) | `REPLAY_GAP requested_after=<n> oldest_available=<n>` | one `{"replayGap": {"requestedAfterSequence": <n>, "oldestAvailableSequence": <n>}}` line, counted toward `-limit` like any other row |
|
||||
| `mxgw-py` (Python) | same JSON dump as `--json` | `{"replayGap": {"requestedAfterSequence": <n>, "oldestAvailableSequence": <n>}}` as one entry of the `events` array |
|
||||
| `mxgw-dotnet` (.NET) | the raw sentinel `MxEvent` as protobuf JSON, including its `replayGap` field | same, as one entry of the `events` array |
|
||||
| `mxgw-java` (Java) | the sentinel's `worker_sequence` and `family` (`0 MX_EVENT_FAMILY_UNSPECIFIED`) | the raw sentinel `MxEvent` as protobuf JSON, including its `replayGap` field |
|
||||
| `mxgw-dotnet` (.NET) | one `{"replayGap": {...}}` line (its "text" mode is JSON-per-line) | the same row — per line with `--jsonl`, as one entry of the `events` array with `--json` |
|
||||
| `mxgw-java` (Java) | `REPLAY_GAP requested_after=<n> oldest_available=<n>` | one `{"replayGap": {"requestedAfterSequence": <n>, "oldestAvailableSequence": <n>}}` line |
|
||||
|
||||
Rust, Go, and Python emit the same two key names and, deliberately, the same JSON
|
||||
value **types**: the cursors are JSON numbers (`7`), not strings. That is why the
|
||||
Go CLI types the row by hand instead of marshalling `ReplayGap` with `protojson` —
|
||||
the proto3 JSON mapping renders 64-bit integers as strings (`"7"`), which is also
|
||||
why the .NET and Java rows, which pass the sentinel through a protobuf JSON
|
||||
formatter, carry **quoted** cursors. A matrix runner must therefore compare parsed
|
||||
values, not raw bytes, and must not assume the same value type across all five
|
||||
CLIs.
|
||||
All five emit the same two key names and, deliberately, the same JSON value
|
||||
**types**: the cursors are JSON numbers (`7`), not strings. That is why every
|
||||
CLI types the row by hand instead of marshalling `ReplayGap` through its
|
||||
protobuf JSON formatter — the proto3 JSON mapping renders 64-bit integers as
|
||||
strings (`"7"`). Normal event rows still come from the protobuf formatters, so
|
||||
a matrix runner must still compare parsed values, not raw bytes, when it mixes
|
||||
gap rows with event rows.
|
||||
|
||||
Two further formatting differences among the three canonical CLIs, none of them
|
||||
semantic: Python sorts object keys and uses `", "` / `": "` separators
|
||||
|
||||
Reference in New Issue
Block a user