| 2026-07-09 |
P2 Epic Wave E2 — typed-command parity (commit bde042b). CLI-04 → In progress (4/5 clients; Java pending in the SAME session — see next note), CLI-30 → Done. Every parity-critical single-item command now has a typed session helper across .NET/Go/Rust/Python: Phase 1 AdviseSupervisory/WriteSecured/WriteSecured2/AuthenticateUser/ArchestrAUserToId, Phase 2 AddBufferedItem/SetBufferedUpdateInterval/Suspend/Activate, plus Unregister (CLI-30: Rust + .NET added; Go/Java/Python already had it — CLI-30 fully Done). Each wraps existing raw-command machinery (no new wire surface) and runs the client's MXAccess-level reply validation (hresult < 0 + MxStatusProxy). MXAccess parity preserved (WriteSecured-before-authenticate surfaces the native failure). Credentials route through each client's secret-redaction seam (never in logs/exceptions/ToString/Debug/Display; each suite asserts a distinctive credential is absent from surfaced errors); new CLI subcommands take credentials via flag/env, never echoed. Verified per toolchain: .NET build clean 102 passed; Go gofmt/vet/build/test clean; Rust fmt/check/test/clippy clean; Python 145 passed. Shared doc: ClientLibrariesDesign.md "Typed Command Parity" section. |
| 2026-07-09 |
Java client toolchain now works locally on the Mac (user-flagged + verified): homebrew openjdk@17 (17.0.19), @21, @26 are installed (off PATH); JAVA_HOME=/opt/homebrew/opt/openjdk@17 gradle test → BUILD SUCCESSFUL. Retires the "Java client must be built on windev" constraint — the remaining Java halves of CLI-15 + CLI-04 are done locally this session (no windev batch). Memory project_java_build_host rewritten. |
| 2026-07-09 |
P2 Epic — TST-04 (session-resilience epic governance) → Done (commit ed3c6c6, docs-only umbrella). Resolved the epic's shipped-vs-planned entanglement into three decisions: Phase 3 finished (Task 13=TST-02 owner-scoped attach P0, Task 15=TST-01 reconnect e2e, Task 14=CLI-15 4/5 clients w/ Java pending); Phase 4 scoped as TST-15 with the Viewer-default decision settled (admin-sees-all, Viewer strict per owned/granted session, matching TST-02's gRPC owner binding); Phase 5 (orphan-worker reattach) DEFERRED, not planned — the CLAUDE.md "gateway restart does not reattach orphan workers" invariant stands and the EnableOrphanReattach flag does not exist / must not be referenced. Updated oldtasks.md, the tasks.json mirror (per-task statuses + governance note), and the CLAUDE.md reconnect paragraph (clients consume ReplayGap; reattach deferred). The actionable slices carry their own verification: TST-01 (done), TST-02 (done, P0), TST-15 (pending, E3). |
| 2026-07-09 |
P2 Epic Wave E1 — reconnect-replay: CLI-15 + TST-01 → In progress (both gated on the Java client, deferred to the windev batch). CLI-15 (commit 0c6e5b3): four clients now surface the gateway's ReplayGap reconnect sentinel as a distinct, typed, non-terminal signal (never synthesized, never swallowed) — .NET MxEventStreamItem/StreamEventItemsAsync (build clean, 87 passed), Go EventResult.ReplayGap+IsReplayGap() (build/vet/test clean), Rust EventItem::ReplayGap enum (EventStream now yields Result<EventItem, Error>; fmt/check/test/clippy clean), Python ReplayGap dataclass yielded from stream_events (131 passed). Shared docs: ClientLibrariesDesign.md non-goals reframed (reconnect-replay protocol is consumable; auto-reconnect stays a non-goal) + CrossLanguageSmokeMatrix.md resume-gap note. Resume contract uniform: after_worker_sequence = oldest_available_sequence - 1. TST-01 server half (commit fed0685): GatewayEndToEndReconnectReplayTests (2 facts) proves the default-on reconnect protocol end-to-end over the real gRPC StreamEvents path via the fake worker — replay-tail-no-gap (capacity 16, mid-batch cursor) and stale-cursor-emits-ReplayGap-first (capacity 3, 6 events force eviction, cursor=1); single-subscriber detach→reconnect, ring survives detach. macOS-verified 2/2 (needs TMPDIR=/tmp — default macOS TMPDIR pushes the CoreFxPipe Unix-socket path past the 104-byte sun_path limit; Windows CI unaffected). No product bugs; server behavior matched the contract exactly. Remaining to close both: Java ReplayGap surface (windev) + Java client consumer for TST-01. |
| 2026-07-09 |
P2 Wave B — worker event hot-path (commit f61c816), windev-verified. WRK-06 → Done: MxStatusProxyConverter caches the four resolved FieldInfo per status type in a static ConcurrentDictionary (the GetField metadata scan ran 4× per status per event on the STA path); GetValue+Convert.ToInt32 still run per event (late-bound RCW); both exception messages byte-identical (missing-field via ResolveField, not cached on throw through GetOrAdd; null-value unchanged). WRK-11 → Done: MxAccessEventQueue.Enqueue takes ownership of the passed MxEvent (stamps WorkerSequence/WorkerTimestamp in place, no Clone()); audited all 3 callers (base/alarm event sinks + provider-mode handler) — each builds a fresh event, none reuse it; MxAccessValueCache.Set now deep-copies its retained Value/SourceTimestamp/Statuses so the cache snapshot never aliases the queue-owned (later serialized) event. WRK-12 → Done: WorkerFrameWriter coalesces the flush across a drained batch (write each frame, one FlushAsync after the batch, then complete all) — preserves the written+flushed completion contract; a burst of N events costs 1 flush not N; on failure the in-flight batch + queue all fail so no caller hangs. IPC-15 → Done: the multi-event WorkerEnvelope body stays unimplemented (wire still one event per worker_event frame); gateway.md Performance section now distinguishes the shipped flush-coalescing from that deferred additive-proto change. Windev: x86 Worker builds clean (fixed a Windows-only TreatWarningsAsErrors CS8604 in the value-cache null-guard that macOS can't surface); Worker.Tests 356 passed / 0 failed / 11 skipped (+4 new: converter cache-reuse, queue ownership-transfer, value-cache snapshot independence, writer batch-flush-once); gateway Tests 815 passed / 1 failed — the 1 is the known windev-environmental SelfSigned-SAN assertion (passes on macOS), and all pipe-harness tests (which also exercise the earlier G-frame gateway frame change + WRK-12 end-to-end over a real pipe) pass. |
| 2026-07-09 |
P2 Wave B — quick Mac items (commit ec6f82b). TST-11 → Done: src/Directory.Build.props single-sources the .NET-side version (Server/Worker/Contracts/tests stamped 0.1.2, was SDK-default 1.0.0) and appends the git short SHA to InformationalVersion (0.1.2+<sha>, guarded so a git-less build still works); verified Server assembly stamps 0.1.2+579282f, Server+Tests build clean. Kept 0.1.2 (matches Contracts + aligned Python/Rust/Go); converging all to a single 0.2.0 cadence left as a release decision. WRK-15 → Done (docs-only path, no x86 build): STA thread-name refs corrected to the actual MxGateway.Worker.STA in docs/WorkerSta.md + docs/MxAccessWorkerInstanceDesign.md, and the stale heartbeat-counter note fixed (CaptureHeartbeat populates queue depth + sequence from the live queue). TST-23 → Done: already resolved by the Wave A gateway.md edit — the bidi Session RPC now sits under a "Future work: not implemented" heading (no "best long-term shape" framing), consistent with the proto. TST-14 left open by design: its only concrete step is deleting the user's untracked, gitignored *-docs-*.md working files (zero repo impact) — surfaced to the user rather than deleting files not created here. |
| 2026-07-09 |
P2 Wave B — dashboard/security (commit e15c3cb). SEC-25 → Done (near-term hardening only; full per-session EventsHub ACL stays deferred to roadmap item 12 / TST-15): DashboardEventBroadcaster redacts tag values from a deep clone of the event before mirroring to SignalR when Dashboard:ShowTagValues is false (default), so the hub seam cannot leak values regardless of the missing ACL. Clears MxEvent.value (the OnDataChange/OnWriteComplete/OperationComplete/OnBufferedDataChange bodies are empty discriminators — values ride in the top-level field, incl. buffered arrays) + the alarm body current_value/limit_value; source event never mutated (shared with gRPC path + replay ring; verified). Makes the formerly-dead ShowTagValues flag live for the mirror. EventsHub TODO(per-session-acl) kept + tied to roadmap item 12. Test DashboardEventBroadcasterTests (3). SEC-30 → Done: docs/Diagnostics.md trimmed to mark opt-in command-value logging NOT YET IMPLEMENTED (no LogCommandValues knob, RedactCommandValue unwired, no values logged); wiring deferred pending secured-bulk redaction (SEC-13), not wired now. Server build clean; Dashboard tests 152/152. |
| 2026-07-09 |
P2 Wave B — gateway event/frame hot-path performance (8 findings). Frame I/O (commit baae59c): GWC-08/IPC-13 gateway WorkerFrameWriter serializes once into one ArrayPool-rented buffer (LE length prefix + payload) and issues a single write (was: second serialization via ToByteArray, separate prefix array, two writes); IPC-14 WorkerFrameReader rents the payload buffer from ArrayPool instead of new byte[] per frame, read/parse length-bounded, returned in finally. Wire format byte-identical, cross-checked against the worker writer/reader. Event/command hot path (commit 5e2e40a): GWC-06 StreamEvents timing via Stopwatch.GetTimestamp()/GetElapsedTime() (no per-event Stopwatch alloc); GWC-07/IPC-05 MapEvent transfers ownership of the inner MxEvent instead of cloning (safe — single-consumer WorkerEvent, MapEvent runs once pre-fan-out, all downstream consumers read-only; verified no post-mapping mutation) and CreateCommandEnvelope drops its redundant second clone (MapCommand already isolated the graph); every load-bearing isolation clone kept; GWC-15 grpc_stream_queue.depth converted from a per-event push counter to an ObservableGauge summing registered channel sources only at scrape time (name/semantics unchanged). Replay ring (commit cf1b3d4): GWC-14 replaces the LinkedList (node alloc per retained event) with a preallocated circular ReplayEntry[] (head+count), preserving ascending order, capacity eviction, time trim, oldest-read/ReplayGap math, both query paths, and the lock. → all Done. Server build clean (0 warnings); per-cluster tests green (WorkerFrameProtocol 10/10 incl. new near-cap round-trip, EventStream/Metrics/Distributor/Mapper 62/62, Distributor/Replay 33/33 incl. 2 new wrap-around cases). Full-suite macOS checkpoint: 769 passed / 44 failed, all 44 the known named-pipe/fake-worker-harness UDS-104-char limit (0 failures in any touched area). Pending: windev run to exercise the frame I/O over a real pipe (the 44 pipe-harness tests are macOS-blind). |
| 2026-07-09 |
P2 Wave B — SEC-03 (dashboard __Host- cookie prefix) → Done (commit 7d42c85). Conditionally restore the prefix instead of a pure doc fix: DashboardServiceCollectionExtensions PostConfigure resolves the cookie name as explicit MxGateway:Dashboard:CookieName override → else __Host-MxGatewayDashboard when SecurePolicy==Always (RequireHttpsCookie true) → else the plain MxGatewayDashboard default; guard never applies __Host- without Secure (browsers drop it). DashboardAuthenticationDefaults.SecureCookieName added; plain name kept as the non-secure fallback. Five stale docs corrected to the conditional contract (gateway.md, GatewayProcessDesign, ImplementationPlanGateway, GatewayDashboardDesign, CLAUDE.md; GatewayConfiguration phrasing tightened). Test DashboardCookieOptionsTests asserts the name flips with RequireHttpsCookie and that an override wins. Server build clean; Dashboard tests 149/149. |
| 2026-07-09 |
P2 Wave A (doc-drift sweep + client version alignment) via parallel agents, on fix/archreview-p2 off main. Version alignment (commit 4fe1917): CLI-18 (.NET <Version>0.1.2</Version>), CLI-21 (Go ClientVersion 0.1.0-dev→0.1.2), CLI-26 (Python __version__→0.1.2), CLI-29 (Rust CLIENT_VERSION→env!(CARGO_PKG_VERSION)) → Done; verified dotnet build + go build/test + cargo check/test/clippy + pytest 127 pass. Doc-drift (commit 06e1046): IPC-06/07/21 + TST-13 (gateway.md envelope sketch → proto-as-truth, six→seven RPCs incl. QueryActiveAlarms in docs/Grpc.md, Session RPC marked not-implemented, stale sketches removed), SEC-09 (dashboard GroupToRole sample Administrator so it passes the validator), SEC-22 (docs/Authentication.md rewritten to the shipped ZB.MOM.WW.Auth.ApiKeys-package pipeline; 18 stale type names removed, grep-verified absent; named gateway types re-verified present), IPC-17 (wrong Python gen dir mxgateway→zb_mom_ww_mxgateway in CLAUDE.md + 3 docs), CLI-12 (Java 21→17), CLI-16 (docs/ClientPackaging.md reconciled with .slnx/Python package name/gradle project names) → Done. Docs-only claims verified against source. 13 findings closed. |
| 2026-07-09 |
Initial tracking doc generated from the six domain remediation designs. All 153 findings Not started. |
| 2026-07-09 |
P0 tier executed via parallel agents. GWC-01/02/03, TST-02, TST-12, CLI-01, CLI-03 → Done (NonWindows build clean; gateway 135/135 targeted tests pass, Go go test ./... + -race pass, Rust test/clippy -D warnings pass). |
| 2026-07-09 |
P0 tier executed via parallel agents. GWC-01/02/03, TST-02, TST-12, CLI-01, CLI-03 → Done (NonWindows build clean; gateway 135/135 targeted tests pass, Go go test ./... + -race pass, Rust test/clippy -D warnings pass). |
| 2026-07-09 |
Windows full-suite temp-file-lock flakiness (discovered via TST-08) → fixed (commit 11a716a). Two shared-state parallel collisions that macOS never surfaces: (1) self-signed cert generation — SelfSignedCertificateProvider now stages the PFX in a unique <path>.<guid>.tmp (was a fixed name that concurrent/interrupted writers collided on); TestHostEnvironmentInitializer defaults the cert path to a per-process temp dir (so the suite never writes shared ProgramData or fights the deployed service); GatewayTlsBootstrapTests moved to a DisableParallelization collection so its process-global env-var mutation can't bleed into parallel tests. (2) AuthStoreHealthCheckTests — reuse the existing TempDatabaseDirectory helper (SqliteConnection.ClearAllPools() before delete) so the Microsoft.Data.Sqlite pool releases the temp .db handle. windev-verified: 3 consecutive full-suite runs all 793 passed / 2 failed, 0 new orphans (was flaky 2–4 fails, count-varying). The 2 stable remaining failures are pre-existing windev-environmental (SelfSignedCertificateProviderTests.GenerateCertificate_HasExpectedSansEkuAndValidity machine-name/FQDN SAN assertion; EventStreamServiceTests…TracksAggregateQueueDepth timing) — both pass on macOS, unrelated to this change. |
| 2026-07-09 |
P1 TST-08 (orphaned testhost) → Done by evidence: the claimed leak does not reproduce. Full ZB.MOM.WW.MxGateway.Tests suite exits cleanly on macOS (0 survivors) and on the Windows dev box (windev, origin/main worktree: 0 new testhost and 0 new ZB.MOM.WW.MxGateway.Worker processes after a full run, isolated by StartTime). Static audit confirms the prime-suspect fixtures already dispose deterministically (WorkerClient cancels its _stopCts + awaits read/write/heartbeat tasks with a 5 s timeout; GatewaySession disposes the client; E2E/harness fixtures use await using). CLAUDE.md "Source Update Workflow" updated to drop the stale "leaves orphaned testhost processes" rationale (filtered runs kept as a speed guideline). Discovered separately (NOT TST-08, still open): Windows-only temp-file-lock flakiness in ~4 full-host test classes — AuthStoreHealthCheckTests (Microsoft.Data.Sqlite connection-pool holds the temp .db handle after await using, so the finally File.Delete throws "used by another process"), GatewayTlsBootstrapTests/DashboardCookieOptionsTests/DashboardHubsRegistrationTests (a gw.pfx.tmp handle from SelfSignedCertificateProvider's fixed-name path+".tmp" atomic-write racing teardown). Count varies run-to-run (2–4 fails); macOS never sees it (Unix allows deleting open files). Fix = SqliteConnection.ClearAllPools() before temp delete + a unique/guarded .tmp name; verify on windev. |
| 2026-07-09 |
SEC-10 polish (gateway-side follow-up to the G-2 auth-lib core) → done. apikey create-key gains an optional --expires (absolute ISO-8601 UTC or relative <N>d/<N>h; omit = non-expiring, opt-in) threaded through ApiKeyAdminCommand/parser/runner into the library's CreateKeyAsync(..., expiresUtc, ...); list-keys shows an expiry column + active/expired/revoked status. Dashboard API Keys page surfaces expiry: an Expires column (Never when unset) and a status badge reading Expired (red) / Expiring (≤7 days, amber) / Revoked / Active (DashboardApiKeySummary.ExpiresUtc projected in DashboardSnapshotService; StatusBadge maps the new states). Server build clean; targeted tests 32/32 (parser abs/relative/invalid + end-to-end past-expiry rejection via the live verifier) + dashboard 28/28. Docs: docs/Authentication.md (verification flow expiry step, CLI table + examples, dashboard badge). SEC-10 was already Done (core); this closes the tracked polish. |
| 2026-07-09 |
P1 Wave 3 (event-channel decoupling). GWC-04 → Done. WorkerClient's read loop awaited EnqueueWorkerEventAsync inline, which blocks in the bounded event channel's timed WriteAsync (≤ EventChannelFullModeTimeout, 5 s) when the channel is full with a slow/absent StreamEvents consumer — stalling any WorkerCommandReply/heartbeat queued behind an event frame, so an in-flight InvokeAsync could hit CommandTimeout despite a timely worker reply. Fix mirrors the existing outbound WriteLoopAsync: an unbounded event staging channel + a dedicated EventWriteLoopAsync; DispatchEnvelope is now fully synchronous and the WorkerEvent branch hands off with a non-blocking TryWrite, so the read loop never awaits event enqueue. The event write loop owns the timed write + the sustained-overflow ProtocolViolation fault (unchanged contract); registered in WaitForBackgroundTasks, completed on close/fault/dispose. Server build clean (0 warnings); non-pipe event tests 37/38 (the 1 is the known parallel-load EventStreamServiceTests…TracksAggregateQueueDepth timing flake — passes in isolation). New pipe-harness test (reply after events with a full consumer-less channel dispatches without CommandTimeout) verified on windev. Docs: GatewayProcessDesign read/write/event-loop section. Commit 32d6b48. Wave 3 complete. |
| 2026-07-09 |
P1 Wave 3 (size/backpressure topology + write ordering). IPC-02/03/04 + WRK-04/07 → Done. Size negotiation (IPC-02): added GatewayHello.max_frame_bytes (regen Generated/ + clients/proto descriptor refresh with pinned protoc 34.1); the gateway sends its negotiated worker-frame max and the worker adopts it (WorkerFrameProtocolOptions.AdoptNegotiatedMaxMessageBytes, 0 = keep default, >256 MiB rejected) instead of a hard-coded default. Headroom (IPC-03): the pipe frame max now sits EnvelopeOverheadReserveBytes (64 KiB) above the public gRPC cap (default Worker.MaxMessageBytes 16 MiB→16 MiB+64 KiB), cross-validated at startup; WorkerClient pre-checks command envelope size and fails only the offending correlation (ResourceExhausted) instead of SetFaulteding the session. Drain bound (IPC-04): gateway request validator rejects DrainEvents max_events above 10 000; the worker caps each reply at MaxDrainEventsPerReply (10 000) and treats max_events = 0 as that cap, not "drain all". Sequence (WRK-04): WorkerFrameWriter stamps the envelope Sequence at the point of writing under the write lock, so wire order and stamped sequence always agree under concurrent producers. Priority (WRK-07): the worker writer is now a cooperative priority scheduler — control frames (reply/fault/heartbeat/shutdown-ack) drain ahead of event frames; per-frame validation/size rejections fail only that frame, a stream failure fails all queued. Docs same-change (GatewayConfiguration, WorkerFrameProtocol, gateway.md). Verified: macOS NonWindows build clean + validator/grpc tests green; windev x86 worker builds clean, Worker.Tests 352 passed / 0 failed / 11 skipped (incl. new monotonic-sequence, control-before-event priority, negotiated-max, drain-bound tests), gateway Tests 799 passed / 3 failed — all 3 pre-existing windev-environmental (SelfSigned SAN + 2 EventStreamServiceTests timing, both pass in isolation). Commits c8b3a22 (gateway half), ebe6aea (worker half), 309296f (descriptor + default-expectation refresh). GWC-04 (event-channel decoupling) is the remaining Wave 3 item. |
| 2026-07-09 |
P1 S-misc (dashboard/observability hardening). SEC-02/12/20 → Done. SEC-02: DashboardAuthorizationHandler restricts the loopback + Authentication:Mode=Disabled bypasses to read-only (they satisfy a Viewer-bearing requirement but never AdminOnly), closing the policy-layer gap where anonymous localhost was authorized for Admin surfaces. SEC-12: DashboardSessionAdminService now emits canonical AuditEvents (dashboard-close-session/dashboard-kill-worker, category SessionAdmin) through IAuditWriter on Success/Failure/Denied, so Close/Kill land durable audit rows. SEC-20: dropped the unbounded session_id tag from the exported mxgateway.heartbeats.failed counter. Docs updated same-change (CLAUDE.md, GatewayDashboardDesign.md, Metrics.md). Server build clean (0 warnings); targeted classes 30/30 pass; broader Dashboard+Security+GatewayApplication+Metrics sweep 295/295 pass. |
| 2026-07-09 |
P1 Wave 2b (security authz+hub). SEC-05/07/08/11 → Done (hub-token lifetime; QueryActiveAlarms scope arm; gateway-side verification cache + last-used coalescing; login rate limit + per-peer gRPC failure limiter). Full-suite checkpoint caught + fixed regressions the earlier narrow SEC-01/04/06 filter missed: cross-platform path-rooting, an IHostEnvironment fallback for minimal DI containers, a test-assembly ASPNETCORE_ENVIRONMENT=Development default, and a platform-correct default-path assertion. Suite: 747 passed / 42 failed, all 42 pre-existing macOS named-pipe-harness env failures. |
| 2026-07-09 |
P1 Wave 2a (security). SEC-01/04/06 → Done (config path-rooting + production validator guards; Server build clean, validator+hygiene tests 53/53). SEC-10 → Done: the shared ZB.MOM.WW.Auth.ApiKeys gained optional ExpiresUtc (expired keys rejected, auth DB auto-migrates to schema v3) via a concurrent HistorianGateway-remediation session's "G-2"; this repo consumes it by bumping the four Auth.* refs 0.1.2→0.1.4 (commit 197731a). Remaining SEC-10 polish (apikey create --expires + dashboard staleness badge) tracked as a small follow-up. |
| 2026-07-09 |
P1 Wave 1 (CI + codegen freshness + Rust buildability) via parallel agents. IPC-01/09/19/20, CLI-02 → Done; TST-03 → In review (CI pipeline authored + YAML/layout-validated, but not yet executed on a Gitea runner — proven on first push). Verified on macOS: NonWindows build clean, ClientProtoInputTests 5/5, publish-client-proto-inputs.ps1 -Check exit 0, cargo package (no --no-verify) compiles standalone. Added a vendored-Rust-proto drift guard (Check 3) to check-codegen.ps1 closing the CLI-02 static-copy risk. IPC-09 script guards not executed end-to-end (need pinned python/JRE toolchains); logic is PATH-resolution + version assertion. |
| 2026-07-09 |
WRK-01 → Done. Verified on Windows host (windev) via an isolated origin/main worktree: worker builds x86 clean, StaRuntimeTests+WorkerPipeSessionTests 33/33 pass. Fixed an xUnit1030 build error (the new worker test used .ConfigureAwait(false) in [Fact] bodies) that the macOS tree could not surface. Also ran GWC-01's Windows-only WorkerClientTests on windev: 18/18 pass (incl. ReadEventsAsync_SecondEnumerator_Throws). All 8 P0 findings now Done. Not yet committed. |