260 lines
27 KiB
Markdown
260 lines
27 KiB
Markdown
# MxAccessGateway — Remediation Plan & Tracking (2026-08-19 review)
|
||
|
||
Source review: [`../00-overall.md`](../00-overall.md) (HEAD `8b3e3b3`, committed as `f4919ba`). Generated 2026-08-20.
|
||
Tracks the 34 cycle-3 IDs (GWC-31+, WRK-32+, IPC-33+, SEC-37+, CLI-46+, TST-31+) plus the tracker-housekeeping actions the overall asked for. Cycle-1/2 trackers remain the record for their own IDs.
|
||
|
||
**Status legend:** `Not started` · `In progress` · `Done` · `Blocked (external)` · `Deferred (P2)` · `N/A`.
|
||
|
||
## Execution model
|
||
|
||
This plan is executed as **seven parallel batches**, each by one subagent working in an isolated git worktree on its own `fix/c3-<batch>` branch, merged back into `main` by the coordinator in the order listed (lowest conflict surface first). Every batch must: build the affected component(s) on macOS (`NonWindows.slnx` — the x86 worker cannot build here), run only the filtered tests it touches, update docs in the same commit, and cite finding IDs in commit messages (`fix(IPC-34): …`). Worker-side changes (batches E, F) are verified afterwards on windev via `windev-worker-ci.ps1 -Mode test`.
|
||
|
||
**Model assignment rationale:** `opus` for batches that change concurrency/authorization logic or require reasoning across several interacting files with regression tests; `sonnet` for contained, well-specified edits with a clear recipe (version bumps, doc reconciliation, a two-line worker fix); `haiku` for none — every batch either touches code invariants or needs judgement about stale prose, where the cost of a wrong mechanical sweep exceeds the saving.
|
||
|
||
| Batch | Branch | Findings | Model | Why this model | Status |
|
||
|---|---|---|---|---|---|
|
||
| A | `fix/c3-client-versions` | CLI-46 | sonnet | Mechanical five-client bump + README note + one script guard; recipe is fully specified | Done |
|
||
| B | `fix/c3-glauth-doc` | TST-31 | sonnet | Reconcile a table against one TOML source of truth, re-derive one default, change an assert to a log | Done |
|
||
| C | `fix/c3-tracker-hygiene` | GWC-31 + housekeeping (close GWC-16/IPC-08/IPC-31, refresh TST-06/TST-17, register WRK-31) | sonnet | Cross-file comment/ID sweep needs care about what each ID *means*, but no logic changes | Done (`3619152`) |
|
||
| D | `fix/c3-dashboard-acl` | SEC-40, SEC-41, GWC-38 | opus | Authorization semantics, fail-closed decisions, claims re-resolution; each needs a regression test | **Done** (`b177636` GWC-38, `2ef7b93` SEC-41+SEC-40, `8257a03` comment fixup; branch not merged/pushed) |
|
||
| E | `fix/c3-ipc-boundaries` | IPC-33, IPC-39, IPC-34, IPC-35 | opus | Changes the WorkerClient command lifecycle, the options validator, and the worker drain budget; race-sensitive | **Done** (`577a0db` IPC-33, `a71663a` IPC-39, `b27035b` IPC-34, `ab41362` IPC-35; branch `fix/c3-ipc-boundaries`, not merged/pushed) — worker half verified on windev (`f2ab9cc`, Worker.Tests 524/524) |
|
||
| F | `fix/c3-worker-residuals` | WRK-32, WRK-33 (+WRK-34 opportunistic) | sonnet | Small, precisely located worker edits + doc prose; cannot be built on macOS so the agent's job is a careful, minimal diff | Done (windev x86 build + Worker.Tests 524/524 green on `f2ab9cc`) |
|
||
| G | `fix/c3-session-lifecycle` | GWC-32, GWC-34, GWC-37 | opus | Distributor/dispose lifecycle races and an alarm-monitor re-resolve path; needs lock-discipline reasoning | Done (`058d8d5`, `282a0e7`, `1932217`) |
|
||
|
||
**Out of scope for this execution (recorded, not dropped):**
|
||
|
||
| ID | Status | Why |
|
||
|---|---|---|
|
||
| TST-32 | Blocked (external) | Gitea runner registration-token reset is a web-UI action on the Gitea admin page; no repo change. Operator to-do. |
|
||
| SEC-37 | Blocked (external) | Family-wide: TLS on the shared GLAuth lives in `scadaproj/infra/glauth/` (separate repo + docker host). Plan separately; after it lands, move the deployed service to `Production`. |
|
||
| CLI-47/48/49/50, IPC-36/37, TST-35 | Not started | Activated by the 2026-08-25 P2 continuation below. |
|
||
| GWC-33/35, SEC-38/39 | Done | Closed by continuation batch I; regression counts and commits are recorded below. |
|
||
| GWC-36, IPC-38, TST-33/34/36 | Done | Closed by continuation batch H; verification and commit are recorded below. |
|
||
| WRK-34 | Done | Completed opportunistically in batch F (`3679e59`): watchdog faults use `CommandMethod=Watchdog` and carry the stuck correlation ID in the diagnostic message. Tracker correction recorded by the continuation audit. |
|
||
|
||
## Batch specifications
|
||
|
||
### A — CLI-46 client release-train bump (sonnet)
|
||
- Bump .NET/Go/Python/Rust clients `0.2.0 → 0.2.1`, Java `0.2.1 → 0.2.2` in every version-bearing file (`pyproject.toml` + `version.py`, `Cargo.toml` workspace + any `version =` consumers, `Directory.Build.props`/csproj `<Version>`, Java `build.gradle`/`gradle.properties`, Go module is tag-driven — update any `Version` const if one exists). Follow `docs/ClientPackaging.md` for the authoritative file list.
|
||
- `clients/python/README.md` + `docs/ClientPackaging.md`: note that published pypi 0.2.0 has a broken `connect()` (event-loop binding, fixed by `a8f86b5`) and is superseded by 0.2.1.
|
||
- Add a PR-time check to `scripts/check-codegen.ps1` (or a new `scripts/check-client-versions.ps1` wired where the other checks run): fail if any `clients/<lang>` source differs from its last publish tag while the version constant still equals that tag's version. Document in `docs/ClientPackaging.md`.
|
||
- Verify: `dotnet build clients/dotnet/...slnx`; `cargo check --workspace`; `python -m pytest` (clients/python); `JAVA_HOME=/opt/homebrew/opt/openjdk@17 gradle test` then **revert** spurious generated-proto churn; `go build ./... && go test ./...`.
|
||
|
||
### B — TST-31 glauth.md + live-test credential (sonnet)
|
||
- Reconcile `glauth.md` against `~/Desktop/scadaproj/infra/glauth/config.toml`: ReadOnly gid, the pre-provisioned users table (drop `readonly/readonly123`, fix `admin` password), the worked example at `:124`. Keep the OPC-UA taxonomy note.
|
||
- Re-derive `MXGATEWAY_LIVE_MXACCESS_WRITE_SECURED_PASSWORD` default in `docs/GatewayTesting.md` and the `?? "admin123"` literal in `WorkerLiveMxAccessSmokeTests.cs` from the config; make the test **log** (not assert) whether `AuthenticateUser` succeeded.
|
||
- Verify: `dotnet build src/ZB.MOM.WW.MxGateway.NonWindows.slnx` (IntegrationTests compiles on mac? if excluded, note it).
|
||
|
||
### C — GWC-31 + tracker housekeeping (sonnet)
|
||
- Sweep code comments citing unregistered `GWC-30`/`GWC-31` (perf pass) in `WorkerClient.cs`, `GatewayMetrics.cs`, `WorkerClientTests.cs`, worker `WorkerFrameReader/Writer.cs` to `PERF-nn` keyed to task numbers in `docs/plans/2026-08-15-perf-review-remediation.md`; add a PERF-ID table to that plan. Do not touch the genuine GWC-30 (frame-reader prefix) citations if any exist.
|
||
- `archreview/REVIEW-PROCESS.md` (or wherever the ID rule lives): state that GWC/WRK/IPC/SEC/CLI/TST prefixes are reserved for archreview registers.
|
||
- Cycle-2 tracker (`archreview/2026-07-12/remediation/00-tracking.md` + domain docs): GWC-16 → Won't fix (rationale from cycle-3 10-gateway-core.md), IPC-08 → Done (`7c1ea12`, residual IPC-34), IPC-31 → Done (superseded by GWC-28), refresh TST-06/TST-17 rows, register WRK-31 (interim ID burned by `e913dab`) so it is never reused.
|
||
- Verify: `dotnet build src/ZB.MOM.WW.MxGateway.NonWindows.slnx`; `dotnet test --filter FullyQualifiedName~WorkerClientTests`.
|
||
|
||
### D — SEC-40, SEC-41, GWC-38 (opus)
|
||
- SEC-41: `DashboardSessionAcl` re-resolves tags from `LdapGroupClaimType` claims via `DashboardGroupTagMapping.MapGroupsToTags` against current options (as `HubTokenService` does) instead of trusting login-stamped tag claims; keep stamped claims only as fallback when no group claims exist (document). Test: principal with stale tag claim + group whose grant was removed → denied.
|
||
- SEC-40: decide **tighten**: `AlarmsHub` gets a dedicated policy requiring a real role claim (anonymous-loopback/Disabled bypass excluded) — and document in `docs/GatewayDashboardDesign.md` ACL section + `docs/GatewayConfiguration.md` GroupToTag row that alarm metadata remains galaxy-wide for authenticated Viewers (central monitor, no per-session provenance). Test for the policy.
|
||
- GWC-38: `GatewayBrowseScopeProvider` throws `RpcException(PermissionDenied)` (and logs) when `Current` is null **and** API-key auth is enabled; unchanged when auth mode is Disabled. Test both branches.
|
||
- Verify: build Server; `dotnet test --filter "FullyQualifiedName~DashboardSessionAcl|FullyQualifiedName~AlarmsHub|FullyQualifiedName~BrowseScope"` (adjust to real class names).
|
||
|
||
**Outcome (done, branch `fix/c3-dashboard-acl`, commits `b177636`, `2ef7b93`, `8257a03`; not merged, not pushed).** Decisions worth carrying forward:
|
||
|
||
- **SEC-41 fallback:** the ACL re-resolves from `mxgateway:ldap_group` claims when the principal has any, and falls back to the stamped `zb:dashboardtag` claims only when it has none. That is exactly the hub-token principal — `HubTokenService.Validate` rehydrates roles and tags but **not** groups, so re-resolution already happened at mint. The fallback cannot re-open the cookie gap, because `DashboardAuthenticator` stamps both claim kinds from one group list.
|
||
- **SEC-40 requirement type:** new `AuthenticatedDashboardRoleRequirement` + `AuthenticatedDashboardRoleHandler` and a `MxGateway.Dashboard.Alarms` policy. `DashboardAuthorizationHandler` is `AuthorizationHandler<DashboardAuthorizationRequirement>`, so it is never invoked for the new type — the same structural device the Secrets UI's `secrets:manage` already relies on. Both hub schemes are retained on the policy.
|
||
- **SEC-40 scope answer:** the `/alarms` Blazor page carries the SAME policy (it reads the central monitor in process — gating only the hub left the disclosure one navigation away), and the side-rail Alarms link is wrapped in an `AuthorizeView` on that policy. `AlarmsHubPublisher` is unchanged and stays unfiltered by design: audience is decided at hub admission and the feed carries no per-session provenance.
|
||
- **GWC-38:** `PermissionDenied` + warning only when `Authentication:Mode=ApiKey`; `Mode=Disabled` still returns unscoped. `GalaxyRepositoryHostWiringTests` phase 1 was changed to push an *unconstrained identity* rather than none — that is production's real unscoped case.
|
||
- New/changed tests: `AlarmFeedAuthorizationTests` (new, 7), `DashboardSessionAclTests` (+5), `GatewayBrowseScopeProviderTests` (+2), `SecretsNavRenderTests` (+2, and it must register the new policy — an unregistered policy name *throws* inside `AuthorizeView` rather than denying). Filtered run over the touched classes: 92 passed / 0 failed; `NonWindows.slnx` builds zero-warning.
|
||
|
||
### E — IPC-33, IPC-39, IPC-34, IPC-35 (opus)
|
||
- IPC-33 option (a): `GatewayOptionsValidator` adds the upper coupling `Worker:MaxMessageBytes ≤ Protocol:MaxGrpcMessageBytes + 2×reserve`; worker `ResolveDrainReplyByteBudget` becomes `MaxMessageBytes − 2×DrainReplyFrameHeadroomBytes` (floor `MaxMessageBytes/2`); update `docs/GatewayConfiguration.md`, `docs/WorkerFrameProtocol.md`. Test: `GatewayOptionsTests` case for the new bound.
|
||
- IPC-39: pre-check compares against `MaxMessageBytes − MaxSequenceEncodingBytes (11)`; fix the comment direction.
|
||
- IPC-34: caller-cancellation arms call `TrySendCancelForAbandonedCommand` (renamed) gated on `removed`, skipped when `_stopCts` is the source; new `WorkerClientErrorCode.CallerCancelled` replacing the `GatewayShutdown` mislabel, mapped to `Cancelled` in the gRPC layer; update `docs/Grpc.md` mapping line, `gateway.md:913-919`, `docs/GatewayProcessDesign.md:596-602`. Test: twin of the timeout test driven by the caller token.
|
||
- IPC-35: `ReadHandshakeEnvelopeAsync` special-cases `WorkerFault` → `WorkerClientException(WorkerFaulted, CreateWorkerFaultMessage(...))`. Test: fake writes `WorkerFault{MxaccessCreationFailed}` instead of `WorkerReady`, category text surfaces.
|
||
- Verify: build Server; `dotnet test --filter "FullyQualifiedName~WorkerClientTests|FullyQualifiedName~GatewayOptions"`. Worker half → windev afterwards.
|
||
|
||
### F — WRK-32, WRK-33 (sonnet)
|
||
- WRK-33: `ObserveFaultWhenever(ObserveCommandTaskAsync(commandTask));` at `WorkerPipeSession.cs:1235` (or catch-all-and-log in the observer).
|
||
- WRK-32: one `pumpStep()` before capturing the `CurrentVersion` baseline in `MxAccessCommandExecutor.cs`; rewrite the executor doc comment (`:996-1003`) to state the recency-based contract; add the same to `docs/MxAccessWorkerInstanceDesign.md` write-completion section and the reply-field comment in `mxaccess_gateway.proto` (**comment-only proto edit → regenerate all generated artifacts in the same commit**, per the repo rule; if regen tooling is unavailable on macOS, skip the proto comment and say so).
|
||
- WRK-34 if trivial: `CreateFault(StaHung, "Watchdog", …)` with the correlation id moved into the message.
|
||
- Cannot build on macOS: keep diff minimal, net48-safe (no init-only/positional records). Verified on windev afterwards.
|
||
|
||
### G — GWC-32, GWC-34, GWC-37 (opus)
|
||
- GWC-32: `DisposeAsync` transitions `_state` to `Closed` under `_syncRoot` before completing channels (or `if (_disposed || IsTerminalState()) return;` in `StageWorkerEvent`); update the XML doc to name all three completion paths. Test: dispose a Ready client mid-dispatch → no `ProtocolViolation` fault/metric.
|
||
- GWC-34: `_eventDistributorDisposed` flag set under `_syncRoot` when nulling; `EnsureDistributorCreated` throws `SessionManagerException(SessionNotReady)` when set. Test: attach after dispose → throws, no silent hang.
|
||
- GWC-37: on `ApplyProviderModeChangeAsync(toMode == Subtag)` re-resolve the watch list and re-subscribe; additionally surface "zero targets resolved while mode can need them" on the provider status (`Degraded` + reason). Update `docs/` alarm-subtag section. Test with the fake worker: GR discovery fails at start, succeeds at failover → watch list non-empty after failover.
|
||
- Verify: build Server; `dotnet test --filter "FullyQualifiedName~WorkerClientTests|FullyQualifiedName~GatewaySession|FullyQualifiedName~AlarmMonitor|FullyQualifiedName~AlarmWatchList"`.
|
||
- **Outcome (Done):** `058d8d5` GWC-32, `282a0e7` GWC-34, `1932217` GWC-37 on `fix/c3-session-lifecycle`. Filtered run 176/176 green; `NonWindows.slnx` clean.
|
||
- GWC-37 **does not re-send** the watch-list on the failover edge. The worker's `AlarmCommandHandler.Subscribe` rejects a second `SubscribeAlarms` while subscribed, and the only expressible replacement (`UnsubscribeAlarms` + `SubscribeAlarms`) rebuilds `FailoverAlarmConsumer` — restarting it on the primary that just failed and discarding the warm standby — so it would flap the feed rather than repair it. The re-resolve happens and any drift is reported on the same status frame as the failover; a monitor restart is the supported way to apply a new list. Adding a watch-list-update worker command is a possible future item, not done here.
|
||
- GWC-37 changes `IAlarmWatchListResolver.ResolveAsync` to return `AlarmWatchListResolution`, and gives `Degraded && Mode==ALARMMGR` a real meaning (empty/undiscoverable standby) with a new dashboard label `Alarm Manager (no subtag standby)`.
|
||
- GWC-32's dispose path now also records `WorkerStopped("dispose")` via the existing once-latch, closing a `workers_running` gauge leak on the dispose-a-Ready-client path. GWC-12's double-dispose interlock got a natural home (the `_disposed` claim moved under `_syncRoot`) but is **not** claimed as fixed.
|
||
|
||
## Merge order
|
||
C is merged **last** (its comment sweep touches the same files E and G edit). Order: A, B, F, D, G, E, C. After merge: full `NonWindows` build + one full gateway test run; then windev worker CI for E+F.
|
||
|
||
## Integration gate (2026-08-20)
|
||
All seven branches merged into `main` (A `ee68cc3`, B `f59c34a`, C `f2ab9cc`, D `9f0c3fd`, E `cfbc995`, F `aa07497`, G `c6650c1`). Merged tree: `NonWindows.slnx` 0 warnings; full gateway suite **1183/1183** passed; windev `windev-worker-ci.ps1 -Sha f2ab9cc -Mode test`: x86 Worker build succeeded, `Worker.Tests` **524 passed / 11 skipped / 0 failed**. Follow-ups surfaced by the batches: a worker command to refresh a live alarm subscription's watch-list (would let GWC-37's re-resolve be applied, not just reported); WRK-32's proto reply-field comment deferred until the next proto regen wave; the five clients are bumped but not yet published.
|
||
|
||
## P2 continuation (planned 2026-08-25)
|
||
|
||
Current-state audit: refreshed `origin/main` and re-checked every deferred finding and integration-gate follow-up. Sixteen of the seventeen P2 findings remain open; WRK-34 was already completed by `3679e59`. All three follow-ups remain open. Exact target client coordinates are still absent from Gitea (HTTP 404), and `clients/go/v0.2.1` does not exist.
|
||
|
||
Approved design: [`../../../docs/plans/2026-08-25-cycle-3-p2-followups-design.md`](../../../docs/plans/2026-08-25-cycle-3-p2-followups-design.md) (`30548da`).
|
||
|
||
Execution plan: [`../../../docs/plans/2026-08-25-cycle-3-p2-followups.md`](../../../docs/plans/2026-08-25-cycle-3-p2-followups.md).
|
||
|
||
The continuation runs serially in the isolated `.worktrees/c3-p2-followups` worktree on `codex/c3-p2-followups`, with a tracker update at every batch boundary. Codex equivalents are selected from the implementation risk: `gpt-5.6-terra`/medium for contained documentation, CI, and client work; `gpt-5.6-sol`/high for concurrency, authorization, protocol, and live alarm lifecycle changes.
|
||
|
||
| Batch | Findings / follow-ups | Codex model | Status | Exit gate |
|
||
|---|---|---|---|---|
|
||
| H — tracker and currency | WRK-34 record, GWC-36, IPC-38, TST-33/34/36 | `gpt-5.6-terra` medium | Done | Currency greps clean; README check in portable CI; NonWindows build clean |
|
||
| I — gateway correctness/security | GWC-33/35, SEC-38/39 | `gpt-5.6-sol` high | Done | Focused regression tests green; NonWindows build clean |
|
||
| J — secondary contracts | IPC-36/37 | `gpt-5.6-sol` high | Done | Shared launch constants and descriptor parity tests green |
|
||
| K — client alarm parity | CLI-47/48/49/50 | `gpt-5.6-terra` high | Done | All five client suites green |
|
||
| L — live watch-list/proto wave | watch-list refresh follow-up + WRK-32 proto comment | `gpt-5.6-sol` high | Done | Codegen clean; portable alarm/contract tests green; windev Worker.Tests green |
|
||
| M — Windows gateway CI | TST-35 | `gpt-5.6-terra` medium | Done | windev `live` mode proves Worker, gateway, full-slnx, and live smoke tiers |
|
||
| N — integration and release | publish five clients + Contracts | `gpt-5.6-sol` high | Done | Full local/windev gates; merged `main`; registry coordinates and Go tag verified |
|
||
|
||
### Continuation tasklist
|
||
|
||
#### H — tracker and currency
|
||
|
||
- [x] Correct WRK-34 from Deferred to Done with commit `3679e59`.
|
||
- [x] GWC-36: correct `EventSubscriberReplayAttachment.OldestAvailableSequence` semantics.
|
||
- [x] IPC-38: add public `DrainEvents` behavior to `docs/Grpc.md` and correct the cycle-2 omission rationale.
|
||
- [x] TST-33: reconcile the five stale/self-contradictory `stillpending.md` claims and mark its live-status boundary.
|
||
- [x] TST-34: run `code-reviews/regen-readme.py --check` in portable CI and qualify the interpreter note.
|
||
- [x] TST-36: replace prose ``event`` scope references with canonical ``events:read``.
|
||
- [x] Record batch-H commit and verification evidence here.
|
||
|
||
Batch-H verification (2026-08-25): `python3 code-reviews/regen-readme.py --check`
|
||
reported the generated README current and consistent; the TST-33 and live-document
|
||
TST-36 stale-pattern greps returned no matches; `docs/Grpc.md` contains the public
|
||
`DrainEvents` contract; and `dotnet build src/ZB.MOM.WW.MxGateway.NonWindows.slnx`
|
||
succeeded with **0 warnings / 0 errors** in 1.59 s. Batch commit: `92aae28`.
|
||
|
||
#### I — gateway correctness and security
|
||
|
||
- [x] GWC-33: unregister terminal clients from the event-queue-depth gauge without shortening fault retention.
|
||
- [x] GWC-35: repair acknowledged-to-active snapshot deltas with a Raise transition and instance identity.
|
||
- [x] SEC-38: feed/consult the aggregate for valid key IDs that overflow the peer partition cap.
|
||
- [x] SEC-39: prove a null effective key ID cannot reset the shared fallback partition.
|
||
- [x] Run focused tests and clean NonWindows build; record counts and commits here.
|
||
|
||
Batch-I verification (2026-08-25): the combined `WorkerClientTests`,
|
||
`GatewayAlarmMonitorAttachOrderTests`, and `ApiKeyFailureLimiterTests` filter passed
|
||
**55/55** tests in 12 s; `dotnet build src/ZB.MOM.WW.MxGateway.NonWindows.slnx`
|
||
succeeded with **0 warnings / 0 errors** in 3.42 s. Finding commits: GWC-33
|
||
`b0156c6`, GWC-35 `7807201`, and SEC-38/SEC-39 `1875426`.
|
||
|
||
#### J — secondary contracts
|
||
|
||
- [x] IPC-36: centralize all six worker-launch environment names in Contracts and consume them on both sides.
|
||
- [x] IPC-36: document variable/config/default mapping and test launcher completeness.
|
||
- [x] IPC-37: add normalized retained-vs-served Galaxy descriptor parity test.
|
||
- [x] Run focused tests and clean NonWindows build; record counts and commits here.
|
||
|
||
Batch-J verification (2026-08-25): the combined `WorkerProcessLauncherTests` and
|
||
`GalaxyContractParityTests` filter passed **10/10** tests in 1 s; the descriptor
|
||
mutation proof identified the changed protobuf message; and `dotnet build
|
||
src/ZB.MOM.WW.MxGateway.NonWindows.slnx` succeeded with **0 warnings / 0
|
||
errors** in 2.20 s. IPC-36/IPC-37 commit: `d6c5a11`.
|
||
|
||
#### K — client alarm-feed parity
|
||
|
||
- [x] CLI-47: make .NET text status flags explicit and document deliberate JSON differences.
|
||
- [x] CLI-48: test provider/snapshot status arms in .NET, Go, and Java; add Go stream-alarm scaffold.
|
||
- [x] CLI-49: export Go aliases for `AlarmProviderStatus` and `AlarmSnapshotStatus`; fix five-arm documentation.
|
||
- [x] CLI-50: stream Python alarm rows incrementally with an unbounded default and bounded opt-in.
|
||
- [x] Run .NET, Go, Python, Rust, and Java client suites; record counts and commits here.
|
||
|
||
Batch-K verification (2026-08-25): `dotnet test
|
||
clients/dotnet/ZB.MOM.WW.MxGateway.Client.slnx` passed **134/134** portable
|
||
tests (1 live test skipped); `go test ./...` passed both tested packages;
|
||
`python -m pytest` passed **169/169** portable tests (1 opt-in TLS test
|
||
skipped); `cargo test --workspace` passed **108/108** tests; and
|
||
`JAVA_HOME=/opt/homebrew/opt/openjdk@17 gradle test` passed **132/132** tests.
|
||
CLI-47/CLI-48/CLI-49/CLI-50 commit: `5cdb3da`.
|
||
|
||
#### L — live watch-list refresh and protobuf wave
|
||
|
||
- [x] Add explicit fallback-enabled subscription semantics for an initially empty discovered list.
|
||
- [x] Add and round-trip `UpdateAlarmWatchListCommand` and its `MxCommandKind`.
|
||
- [x] Route the command through the worker executor and alarm handler on the STA.
|
||
- [x] Build/subscribe/attach a replacement standby before swap; preserve the old standby on failure.
|
||
- [x] Preserve current primary/subtag mode during a successful replacement.
|
||
- [x] Re-resolve on the existing gateway reconciliation cadence and send only material changes/recovery.
|
||
- [x] Refresh immediately at failover edge, update acknowledged fingerprint only after worker OK, and reconcile after success.
|
||
- [x] Expand WRK-32's public reply-field comment to the sequential stale-callback/recency case.
|
||
- [x] Replace IPC-36's internal env-var name in the proto comment with the public configuration key.
|
||
- [x] Regenerate Contracts and all client generated trees once; run codegen and all affected suites.
|
||
- [x] Verify x86 Worker build and Worker.Tests on windev; record SHA/counts here.
|
||
|
||
Batch-L verification (2026-08-25): `pwsh scripts/check-codegen.ps1` passed all
|
||
four descriptor/C#/Rust/Go/Python freshness checks, and Java
|
||
`checkGeneratedClean` passed. The exact portable alarm/contract/descriptor
|
||
filter passed **77/77**; `NonWindows.slnx` built with **0 warnings / 0 errors**;
|
||
the .NET, Go, Python, Rust, and Java client suites were green (respectively
|
||
**134 passed / 1 live skip**, both Go packages, **169 passed / 1 opt-in TLS
|
||
skip**, **108 passed**, and **132 passed**). Windev `test` mode at
|
||
`986c6c0ce4f02c62b4f59ec44780de5af6d291b8` built the x86/net48 Worker with
|
||
**0 warnings / 0 errors** and passed Worker.Tests **529 passed / 11 opt-in
|
||
skips / 0 failed**. Feature/proto commit: `484028e`; Batch-J x86 compile
|
||
follow-up: `986c6c0`.
|
||
|
||
#### M — Windows gateway CI
|
||
|
||
- [x] TST-35: add the serialized net10 gateway suite to windev `live` mode.
|
||
- [x] Update `docs/GatewayTesting.md` and `scripts/ci/README.md` with order/failure semantics.
|
||
- [x] Execute `live` mode on windev and record Worker, gateway, full-slnx, and live-smoke evidence here.
|
||
|
||
Batch-M verification (2026-08-25): windev `live` mode at exact commit
|
||
`cc143b52cf04be0b2f08350922a987b2e250bc1d` completed the serialized sequence in
|
||
**4m45s** with remote exit code 0. The x86/net48 Worker build succeeded with **0
|
||
warnings / 0 errors** in 22.59 s; Worker.Tests passed **529**, skipped **11**
|
||
opt-in probes, and failed **0**; the full Windows `slnx` build succeeded with **0
|
||
warnings / 0 errors** in 43.24 s; the net10 gateway suite passed **1193/1193**
|
||
in 53 s; and the live-MXAccess smoke passed **8/8** in 1m46s. TST-35 commit:
|
||
`cc143b5`.
|
||
|
||
#### N — integration and release
|
||
|
||
- [x] Run `git diff --check`, codegen, client-version, README, NonWindows build, and full gateway suite gates.
|
||
- [x] Run all five client suites on the final candidate.
|
||
- [x] Run final windev `live` gate at the exact candidate SHA.
|
||
- [x] Merge/push the verified continuation to `main`; wait for green CI.
|
||
- [x] Re-query all package coordinates and Go tag immediately before publish; abort on collision.
|
||
- [x] Publish .NET Client + Contracts 0.2.1, Python 0.2.1, Rust 0.2.1, Java 0.2.2.
|
||
- [x] Create/push `clients/go/v0.2.1` at the exact release commit.
|
||
- [x] Verify every registry coordinate and Go module/tag, update `docs/ClientPackaging.md`, and record immutable release evidence here.
|
||
|
||
Batch-N portable verification (2026-08-25): `git diff --check`, codegen freshness,
|
||
client-version freshness, and the generated README check all passed without changing
|
||
the worktree. `NonWindows.slnx` built with **0 warnings / 0 errors**; the gateway
|
||
suite passed **1193/1193**, and the portable integration suite passed **5** with
|
||
**19** live-only skips. The final .NET, Go, Python, Rust, and Java client gates were
|
||
green (respectively **134 passed / 1 live skip**, all Go packages built/tested with
|
||
clean `gofmt`, **169 passed / 1 opt-in TLS skip** from a clean virtual environment,
|
||
**108 passed** plus clean `cargo fmt`/Clippy, and **132 passed / 0 failed** with the
|
||
generated Java tree unchanged).
|
||
|
||
Batch-N integration/release verification (2026-08-25): `main` was integrated and
|
||
released at exact commit `5776021970cbbe59813ba57579abe00d9fc61a46`; Gitea CI
|
||
run **783** concluded success. Windev `live` mode at that SHA built the x86/net48
|
||
Worker with **0 warnings / 0 errors**, passed Worker.Tests **529 passed / 11
|
||
opt-in skips / 0 failed**, built the full Windows solution with **0 warnings / 0
|
||
errors**, passed the Windows gateway suite **1193/1193**, and passed the live
|
||
MXAccess smoke **8/8**. One preceding full-suite attempt hit a transient fake-worker
|
||
disconnect in the reconnect/replay test; the test then passed **50/50** isolated
|
||
macOS runs and **20/20** isolated windev runs before the clean full-gate pass.
|
||
|
||
Immediately before publication, all five package coordinates returned HTTP 404
|
||
and `clients/go/v0.2.1` was absent locally/remotely. The published coordinates are
|
||
NuGet `ZB.MOM.WW.MxGateway.Client` **0.2.1** and
|
||
`ZB.MOM.WW.MxGateway.Contracts` **0.2.1**, PyPI
|
||
`zb-mom-ww-mxaccess-gateway-client` **0.2.1**, Cargo
|
||
`zb-mom-ww-mxgateway-client` **0.2.1**, and Maven
|
||
`com.zb.mom.ww.mxgateway:zb-mom-ww-mxgateway-client` **0.2.2**. Each exact Gitea
|
||
package API coordinate returned HTTP 200 after publication. Annotated Go tag
|
||
`clients/go/v0.2.1` resolves locally, remotely, and through `go list -m` to
|
||
`5776021970cbbe59813ba57579abe00d9fc61a46`.
|