| 2026-07-13 |
Initial tracking doc generated from the six domain remediation designs. All 47 findings Not started (IPC-31, SEC-35 N/A). |
| 2026-07-13 |
TST-25/TST-26 → In progress (branch fix/tst-25-windev-ci). Added scripts/ci/{windev-worker-ci.ps1,run-windev-ci.sh,windev.known_hosts}, windows-x86 (per-push) + nightly-windev (scheduled) jobs in ci.yml, and the TST-26 doc/comment fixes (GatewayTesting.md, Contracts.md, check-codegen.ps1). Mechanism hand-verified on windev: build→0, bogus-SHA→nonzero (lock released), test→356 passed/0 failed in ~50s (per-push stays test, no demotion), and run-windev-ci.sh SSH+EncodedCommand exit-code propagation confirmed. |
| 2026-07-13 |
Operator bring-up complete: dedicated CI ed25519 key installed in windev administrators_authorized_keys (authorized into dohertj2, which owns the working MXAccess/toolchain env — a fresh OS account would break the build; the key is independently revocable), Gitea secrets WINDEV_SSH_KEY/WINDEV_SSH_KNOWN_HOSTS + variable WINDEV_SSH_USER=dohertj2 stored, runner→10.100.0.48:22 egress verified on the traefik net, issue-write confirmed. TST-25/TST-26 → Done: credentialed windows-x86 ran GREEN on d769244 (Gitea run #37) — Linux runner SSHed windev, checked out the SHA in C:\build\mxaccessgw-ci under lock, ran the x86 Worker build + Worker.Tests, exit 0; nightly-windev correctly skipped on the push event. Branch merged to main. Follow-ups (old tracker): revisit TST-05 (scheduled live smoke — now covered by nightly-windev) and TST-24 (client wire tests) which this unlocks. |
| 2026-07-13 |
Ran the TST-25 acceptance checks (scripts/ci/README.md) — they caught two real CI defects, both fixed on fix/tst-25-ci-key-log-leak: (1) CI SSH key leaked in cleartext in the windows-x86 step env echo (Gitea's line-oriented masker missed the multiline PEM) — rotated the CI key on windev (old pubkey revoked), stored the key base64-encoded so the masker redacts it to *** (confirmed on run #38), taught run-windev-ci.sh to decode, dropped the redundant public known-hosts secret from the job env; (2) bootstrap lock race — run-windev-ci.sh's pre-hand-off git fetch/checkout ran outside the worktree lock, so concurrent runs collided on .git/index.lock; the bootstrap now holds the lock (ps1 re-uses it via MXGW_CI_LOCK_HELD), retest confirmed clean serialization. Also deflaked SessionManagerTests fail-fast timing assertions (absolute <100ms wall-clock bound flaked under CI load; now anchored to the configured timeout / dropped for the zero-timeout case). Checks passed: unreachable-host fast-fail (exit 255/15s), deliberate-red propagation (Worker.Tests failure → exit 1), lock concurrency (2nd run waits), no-key-in-logs (masked). Merge target df7e20d verified GREEN via the local windev path (Worker build + 356 tests); merged to main 19cbf7b. Check 6 (forced-failure nightly issue): issue endpoint+token proven live at bring-up (#124); in-CI forced-failure probe abandoned to shared-runner congestion (residual if: failure() gating is standard Actions). |
| 2026-07-13 |
New finding TST-30 (Low/P2) added — surfaced during TST-25 acceptance: CI runs on a single shared gitea-runner (maxParallel=1, co-located 10.100.0.35) interleaved with dohertj2/lmxopcua, and Gitea 1.26 exposes no run cancel/delete, so queue latency is unbounded under cross-repo contention and the runner is a single point of failure. Design: add a second/labelled runner + document the no-cancel reality and the run-windev-ci.sh bypass. Roll-ups updated (Testing Low 2→3, total 47→48; P2 9→10). |
| 2026-08-07 |
TST-29 → Done: migrated the Phase-5 (orphan-worker reattach) deferred-not-planned governance record and the settled Phase-4 Viewer-default decision from oldtasks.md into a new "Session-Resilience Epic Scope" entry in docs/DesignDecisions.md; repointed CLAUDE.md and stillpending.md:7,165 from oldtasks.md to docs/DesignDecisions.md / docs/plans/2026-06-15-session-resilience.md.tasks.json; git rm oldtasks.md. The five untracked root docs-review artifacts (MxAccessGateway-docs-{issues,fixed,final}.md, MxGatewayClient-docs-{issues,fixed}.md) were absent from this worktree — delete from the main working tree separately. |
| 2026-08-07 |
GWC-24 → Done (branch fix/gwc-24-staging-bound). WorkerClient._eventStaging is now Channel.CreateBounded at 2 × EventChannelCapacity (Wait, single reader/writer, no sync continuations); a rejected staging TryWrite faults the client ProtocolViolation with QueueOverflow("worker-event-staging") unless IsTerminalState() (shutdown stays a silent drop), so a consumer draining slower than its worker produces dies at a fixed ceiling instead of growing gateway memory. Queue-depth accounting moved from EnqueueWorkerEventAsync to StageWorkerEvent, so the single gauge reports staged + queued; the timed-write fault (EventChannelFullModeTimeout / QueueOverflow("worker-events")) is unchanged and still catches the full-stall case first. No new config key — total gateway-side buffering is 3 × MxGateway:Events:QueueCapacity, derived; coordination with still-open old GWC-21 (EventChannelFullModeTimeout configurability) remains open and was not blocked on. Docs same commit: GatewayProcessDesign.md (two overflow faults), MxAccessWorkerInstanceDesign.md, GatewayConfiguration.md, Metrics.md. Tests: WorkerClientTests.StagingChannelOverflowFaultsWorkerWithoutWaitingForFullModeTimeout and .WorkerEventQueueDepthGaugeCountsStagedEvents; WorkerClientTests 22/22 green, NonWindows.slnx builds with 0 warnings. |
| 2026-08-07 |
ReplayGap end-to-end cluster (GWC-25 + CLI-35 + CLI-36) → Done on fix/gwc-25-replaygap-trio. GWC-25: SessionEventDistributor.RegisterWithReplay's empty-ring branch now reports oldestAvailableSequence = _highestSequenceSeen + 1 when gap == true (still 0 when no gap), so the universal oldest - 1 resume formula no longer wraps to ulong.MaxValue and dead-stream the subscriber; docs/Sessions.md documents the empty-ring value. CLI-35: the Python CLI renders a ReplayGap as a {"replayGap": {...}} row via a new _event_row helper instead of crashing in MessageToDict. CLI-36: the Go CLI branches on result.IsReplayGap() and prints the typed REPLAY_GAP requested_after=<n> oldest_available=<n> line / replayGap JSON row instead of formatting the library's cleared Event. docs/CrossLanguageSmokeMatrix.md gained a per-CLI gap-rendering table (one edit covering both client findings). Four new tests as designed (3 × SessionEventDistributorTests, GatewayEndToEndReconnectReplayTests.ReconnectAfterFullAgeEvictionResumesWithSentinelFormula) plus test_stream_events_renders_replay_gap (Python) and TestRunStreamEventsPrintsReplayGap (Go); all written red first and each reproducing its defect verbatim. Deferred: GWC-25's ReplayGap.oldest_available_sequence proto-comment amendment is not in this change — it is comment-only but triggers the full five-client regen fan-out, so it lands with the later codegen wave (alongside IPC-23's proto-comment edits) rather than forcing a regen for one sentence. Note for that wave: the fake-worker gateway e2e suite cannot run on the macOS worktree without TMPDIR shortened (macOS caps the Unix-domain-socket path backing .NET named pipes at 104 chars; TMPDIR=/tmp dotnet test … works and was used here). |
| 2026-08-07 |
GWC-27 → Done, GWC-26 → Done (branch fix/gwc-26-27-alarm-attach). GWC-27: GatewaySession.AttachInternalEventSubscriber now mirrors AttachEventSubscriber's readiness gate under _syncRoot, before EnsureDistributorCreated, so a premature attach can no longer latch a poisoned distributor. GWC-26: the alarm monitor takes its internal lease directly from the session before SubscribeAlarms and drains it after the first reconcile; ISessionManager.ReadAlarmEventsAsync removed (zero remaining callers); ApplyReconcile now broadcasts an Acknowledge feed transition for a both-present alarm whose state advanced to ActiveAcked (feed-level repair on AlarmFeedMessage, not MxEvent synthesis). New tests GatewaySessionTests.AttachInternalEventSubscriberBeforeReadyThrowsAndDoesNotPoisonDistributor and GatewayAlarmMonitorAttachOrderTests (TransitionsDuringSubscribeWindow_StillReachTheAlarmFeed, ApplyReconcileBroadcastsAcknowledgeDelta); the alarm-monitor fakes now hand the monitor a real Ready GatewaySession with a dashboard mirror so the window is actually reproducible. Verification: NonWindows build 0 warnings/0 errors; GatewayAlarmMonitor 16 passed, SessionManagerTests 38 passed, GatewaySessionTests 19 passed, AlarmFailoverEndToEndTests 2 passed. |
| 2026-08-07 |
Code review of fix/gwc-26-27-alarm-attach surfaced a known pre-existing characteristic, now documented: the alarm monitor's reconcile-derived feed repairs are at-least-once, not exactly-once. A reconcile reads the worker's current state while the matching live transition may still be buffered in the monitor's internal lease, so both broadcast and the duplicates are indistinguishable on the alarm feed (StreamAlarms + dashboard alarm hub). This pre-dates GWC-26 — the Raise/Clear presence repair has always had it, since nothing serializes a reconcile pass against the in-flight live stream — so closing it (reconcile/live serialization or transition-timestamp dedup) was ruled out of scope for a P2 fix. Documented instead in GatewayAlarmMonitor.ApplyReconcile, gateway.md, and docs/Sessions.md, with the consumer-side contract stated explicitly (apply transitions idempotently — "set this alarm to this state", never increment/toggle). Candidate finding for the next review cycle. |
| 2026-08-07 |
CLI-37 + CLI-38 -> Done (branch fix/cli-37-38-conformance), one cross-client conformance commit; closes old-tracker CLI-08. Canonical rules landed everywhere: an MxStatusProxy entry fails iff category != MX_STATUS_CATEGORY_OK (success is the raw COM member, diagnostics only; absent entry = success, present entry with UNSPECIFIED = failure), and a reply fails on HRESULT iff hresult is present and < 0 (so S_FALSE = 1 passes). Edits: .NET MxStatusProxyExtensions.IsSuccess (drop the Success != 0 conjunct) + MxCommandReplyExtensions (!= 0 -> < 0); Go StatusSucceeded (category) + errors.go (< 0); Java MxStatuses.succeeded (category, Javadoc corrected) + MxGatewayErrors (< 0); Python errors.py (category); Rust ensure_mxaccess_success (category, doc comment corrected). Four shared fixtures added under clients/proto/fixtures/behavior/command-replies/ (write.status-category-{error-success-set,ok-success-zero}.reply.json, write.hresult-{s-false,e-fail}.reply.json) + manifest + docs/ClientBehaviorFixtures.md; each of the five suites now runs all four fixture-driven, plus a per-language table test for the two edges fixtures cannot express (nil/null entry, UNSPECIFIED category). Docs same commit: ClientLibrariesDesign.md per-item rule sentence (its existing HRESULT < 0 claim is now true), .NET/Go/Java README error sections. Also fixed a Java test fake that built a status with a bare setSuccess(1) and no category. Verification: dotnet build 0 warnings + 110 passed/1 skipped; gofmt -l clean, go build ./..., go test ./... all ok; gradle test BUILD SUCCESSFUL with no generated-file churn to revert this time (no .proto changed and generateProto stayed up to date); python -m pytest 155 passed/1 skipped; cargo fmt (no unrelated reformat), cargo check, cargo test --workspace 100 passed, cargo clippy --all-targets -- -D warnings clean. Gateway-side ClientBehaviorFixtureTests 8/8 re-run because the new fixtures are validated there. |
| 2026-08-07 |
CLI-45 → Done on fix/cli-45-credential-envvar. All five CLIs now share one credential contract for authenticate-user: flags --password / --password-env (Go: -password / -password-env) defaulting to env MXGATEWAY_VERIFY_PASSWORD, resolution flag-then-env, and a resolved credential that is missing or empty is a usage error naming the flag and the variable — never the value, never sent to the wire. Go and Java previously authenticated with an empty password: Go now returns the guard error before dialing, Java throws a picocli ParameterException instead of falling back to "". Python's --password-env gained the canonical default (its UsageError was already conformant) and its message now names the resolved variable. Rust treats an empty --password or empty env value as missing (resolution extracted into a testable resolve_verify_user_password). .NET adopted the canonical flags and keeps its pre-existing names as deprecated aliases for one release — order: --password, --verify-user-password, the variable named by --password-env (or the deprecated --verify-user-password-env; default MXGATEWAY_VERIFY_PASSWORD), then MXGATEWAY_VERIFY_USER_PASSWORD. Tests: TestRunAuthenticateUser{RejectsEmptyPassword,ReadsPasswordFromCanonicalEnv} (Go), 3 picocli cases (Java), 3 click cases (Python), 2 clap/resolver cases (Rust), 4 xUnit cases covering the canonical flag, both env-name paths, the deprecated flag+env aliases, and the missing/empty failure (.NET). Docs same commit: docs/CrossLanguageSmokeMatrix.md gained a "Credential contract for authenticate-user" section and the per-CLI subcommand-coverage table — the half of this finding that is documented rather than fixed (.NET exposes all nine single-item session commands; Rust unregister + the credential pair; Go/Python/Java the credential pair only; verified against each dispatch table, and every gap is CLI surface only since all five libraries implement all nine helpers). All five client READMEs name the canonical variable and the fail-fast rule; the .NET README gained an authenticate-user credentials section carrying the deprecation note. Deviation: Java keeps isBlank() (per this design's "null or blank" wording for Java) where the other four test emptiness, so a whitespace-only credential is additionally rejected there. Verification (all five, on macOS): Go gofmt -l . clean, go build ./... clean, go test ./... ok; Java JAVA_HOME=/opt/homebrew/opt/openjdk@17 gradle test BUILD SUCCESSFUL, CLI suite 51 tests / 0 failures — no generated-tree churn appeared this run, git status for clients/java/**/generated clean with no revert needed (no .proto changed); Python python -m pytest 148 passed / 1 skipped (TLS opt-in); .NET dotnet build …Client.slnx 0 warnings / 0 errors and client tests 108 passed / 1 skipped (live-gateway opt-in); Rust cargo fmt (diff confined to the new code), cargo check --workspace, cargo test --workspace 100 tests across 6 targets all green, cargo clippy --all-targets -- -D warnings clean. |