Skip to content

fix(dashboard): topology reflects connection health + clears finished requests - #7672

Merged
diegosouzapw merged 2 commits into
diegosouzapw:release/v3.8.49from
danscMax:fix/topology-live-health
Jul 19, 2026
Merged

diegosouzapw merged 2 commits into
diegosouzapw:release/v3.8.49from
danscMax:fix/topology-live-health

Conversation

@danscMax

Copy link
Copy Markdown
Contributor

What

The home-dashboard provider topology only coloured nodes from live/recent traffic.
Between requests — and right after a restart — the map went blank even though 50+
connections were healthy, which reads as "I lost all my providers". Two independent
root causes, fixed together.

1. Stuck-green latch (live pipeline)

request.completed / request.failed are declared in the dashboard event map and
consumed by useLiveRequests to drain the active-request set, but they were never
emitted
— only request.started was (chatCore.ts:410). So a node's green "active"
pulse was a one-way latch: it lit on request start and only cleared on a page reload,
accumulating over a session and disappearing on restart.

Fix: emit the terminal event from persistAttemptLogs (the per-attempt completion
point, correct for both streaming and non-streaming), keyed by the same traceId as
request.started, via a pure resolveRequestLifecycleEvent() helper (2xx/3xx and no
error ⇒ request.completed, else request.failed). Deferred with setImmediate off
the response hot path, mirroring request.started.

2. No at-rest state (visualisation)

The map had nothing to show when idle. Each node is now coloured by connection
health
(green connected / red error / grey idle) as a base layer; live and recent
traffic still take precedence and pulse brighter on top. edgeStyle() gains an
optional trailing healthy param (static dim green) and StatusDot a pulse prop
(static dot for connected-at-rest) — both backward compatible, so the Combo/Compression
studios that share the flow palette are unaffected. Legend "Active" → "Connected".

Validation (Hard Rule #18)

  • tests/unit/topology-request-lifecycle-emit.test.ts — resolveRequestLifecycleEvent
    success / failure / token-alias units + guards that the emit exists and that
    traceId is threaded into persistAttemptLogs (pairs with request.started).
  • tests/unit/topology-connection-health.test.ts — health derivation + node/edge wiring.
  • tests/unit/ui/edgeStyles.test.ts — new healthy edge variant + error > active > last > healthy precedence.
  • npm run typecheck:core clean; npm run lint clean; existing topology/edge suites green (Node + Vitest).
  • Verified the live WS pipeline on a running instance: firing a real request delivered
    request.started on the dashboard WS, confirming the in-process eventBus → embedded
    WS-server path works. The new terminal emit rides the exact same path and is unit-tested.
  • Node states rendered and eyeballed in light and dark themes (connected/active/error/idle).

Scope

No API or DB-schema changes. Security- and PII-sensitive paths untouched. Helper
signature additions are backward compatible.

… requests

The provider topology only lit nodes from live/recent traffic, so between
requests (and right after a restart) it went blank even though 50+ connections
were healthy — which reads as "lost providers". Two root causes:

1. Stuck-green latch: request.completed/request.failed are declared in the
   dashboard event map and consumed by useLiveRequests to drain the active-request
   set, but they were never emitted (only request.started was). A node's green
   "active" pulse therefore only cleared on a page reload, and accumulated over a
   session. Emit the terminal event from persistAttemptLogs — keyed by the same
   traceId as request.started — through a pure resolveRequestLifecycleEvent()
   helper (2xx/3xx + no error => completed, else failed).

2. No at-rest state: the map had nothing to show when idle. Colour each node by
   connection health (green connected / red error / grey idle) as a base layer,
   with live/recent traffic still taking precedence and pulsing brighter on top.
   edgeStyle() gains an optional trailing `healthy` param (static dim green) and
   StatusDot a `pulse` prop (static dot for connected-at-rest); both backward
   compatible. Legend "Active" -> "Connected".

Tests: resolveRequestLifecycleEvent success/failure/token-alias units, edgeStyle
healthy variant + precedence, and source guards for the emit wiring (traceId
threaded into persistAttemptLogs) and the health-colour wiring.
@danscMax
danscMax requested a review from diegosouzapw as a code owner July 18, 2026 06:57
@gemini-code-assist

Copy link
Copy Markdown
Contributor

Warning

You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again!

Resolve conflicts in HomeProviderTopologySection.tsx (keep i18n-compliant
tCommon("active") label, add PR's status field) and edgeStyles.ts (keep
PR's healthy-state branch stacked on release's idle color/opacity update);
repair a stale duplicate assertion in edgeStyles.test.ts left by the
automerge (var(--color-border)/0.2 -> var(--color-text-muted)/0.3).

Co-authored-by: Diego Rodrigues de Sa e Souza <diegosouzapw@users.noreply.github.com>
@diegosouzapw

Copy link
Copy Markdown
Owner

Thanks for tracking down both root causes — the "stuck green" latch is confirmed real (grepped the release branch: request.completed/request.failed are declared in types.ts but were never emitted anywhere before this PR). resolveRequestLifecycleEvent and the edgeStyle/StatusDot unit tests all pass for me locally (17/17 across the three files).

Two things to fix before merge:

  1. The branch currently has real conflicts against release/v3.8.49 in HomeProviderTopologySection.tsx and edgeStyles.ts (a sibling PR already landed the "Active"→i18n tCommon("active") swap and bumped idle edge opacity 0.2→0.3). Please rebase; keep your healthy state addition but reuse the i18n legend and the new idle opacity.
  2. Your new legend label ("Connected") is hardcoded English — please route it through next-intl like the rest of that component instead of a literal string, since the sibling change on release already moved "Active" into the message catalog.

Note: the pure logic (resolveRequestLifecycleEvent, edgeStyle precedence, per-provider health derivation) is unit-tested and I ran it green — nice work there. The on-screen coloring/pulsing itself is UI-only and I haven't visually verified it on a running instance; a screenshot or two (light+dark) alongside your existing claim would help reviewers confirm.

@diegosouzapw

Copy link
Copy Markdown
Owner

Good news — the two conflicts from last review are resolved now. CI is currently red, but that's a shared base/infra issue hitting the whole PR queue right now (confirmed identical failure signature on an unrelated PR), not something in your diff. We still owe you a check on the i18n label item flagged earlier; will confirm once the base-red is cleared and CI re-runs green.

diegosouzapw added a commit that referenced this pull request Jul 19, 2026
… (owner-approved)

The /fix-prs validation-train sweep surfaced a cluster of otherwise-clean
contributor feature PRs (#6973/#7683/#7662/#7672/#7633/#7767) whose per-PR
+1/+2 own-growth collectively exceeded the tip's 3-unit complexity slack
(2056 vs 2059). This was the 4th such block of the day (#7695/#7747/#7768
each needed helper extraction earlier). Owner approved raising both ceilings
to give new-feature PRs breathing room: complexity to 2072 (combined-cluster
2068 + 4 headroom), cognitive to 900 (combined 896 + 4). Structural shrink
stays debt (#3501); tighten via --update next cycle.
@diegosouzapw

Copy link
Copy Markdown
Owner

Validated in local merge-train runs 4+5 on 192.168.0.113 @ a00def8f1/477d9f4d3 (11-PR batch: static gates green ×2; test:unit union green — 24512/24529 + 24504/24521, residual fails proven environmental (/tmp stale) + timing-flake (6/6 isolated); vitest 260/260 on the equivalent local tree). Suite logs: /srv/omniroute-train/.claude/worktrees/merge-train-20260719-{231?,233341}-suite.log + /tmp/mt-full.log

@diegosouzapw
diegosouzapw merged commit 18a8da6 into diegosouzapw:release/v3.8.49 Jul 19, 2026
4 of 5 checks passed
@diegosouzapw diegosouzapw mentioned this pull request Jul 23, 2026
nguyenha935 added a commit to nguyenha935/OmniRoute that referenced this pull request Jul 25, 2026
…t contract

The Recent Requests panel added five `home` keys to en.json but only vi.json was
translated, so the en↔locale key-parity guard (diegosouzapw#6695) failed. Run the sanctioned
`i18n:sync-ui` to mirror them into the remaining 41 locales; untranslated entries
carry the standard `__MISSING__:<en>` marker, which `deepMergeFallback` renders as
the clean English value until a translation pass lands. vi.json keeps its real
translations.

Also rewrite tests/unit/topology-connection-health.test.ts. It guarded diegosouzapw#7672's
connection-health base layer (healthy-but-idle drawn green), which this branch
deliberately replaces with a calm-at-rest map: only live traffic or a real error
lights a node. The test now pins the current contract instead — enabled-connection
gating, no ghost nodes from all-time call_logs, neutral border at rest, dots only
for traffic/errors, and stable alphabetical ring slots so layout never depends on
activity. Legibility is preserved structurally (presence + stable position) rather
than by a rest colour.
nguyenha935 added a commit to nguyenha935/OmniRoute that referenced this pull request Jul 25, 2026
The topology rework replaces the connection-health rest layer from diegosouzapw#7672 with a
calm-at-rest map (only live traffic or a real error lights a node/edge), but three
existing guards still asserted the previous behaviour:

- ui/edgeStyles: pinned the pre-retune rest opacities (last 0.6 / idle 0.3 and a
  healthy 0.4 green base). Retuned to the shipped values and extended with a
  relationship invariant so any future retune must keep every resting state well
  below live traffic in both opacity and stroke width.
- ui/home-provider-topology-section-4606: looked for a Card wrapper. The section's
  frame is now a bordered but transparent div (an opaque surface hid the page's
  graph-paper wallpaper behind the graph), so the framing contract is asserted
  directly, and the Recent Requests child is covered including its gate flag.
- call-logs-exclude-tests-allowlist: dropped an explicit `any` on the row mapper;
  getCallLogs already returns a typed row, so the annotation was unnecessary.

The coverage is kept as real regression guards for the new design rather than
deleted, and each file documents what changed and why.
HouMinXi pushed a commit to HouMinXi/OmniRoute that referenced this pull request Aug 2, 2026
… (owner-approved)

The /fix-prs validation-train sweep surfaced a cluster of otherwise-clean
contributor feature PRs (diegosouzapw#6973/diegosouzapw#7683/diegosouzapw#7662/diegosouzapw#7672/diegosouzapw#7633/diegosouzapw#7767) whose per-PR
+1/+2 own-growth collectively exceeded the tip's 3-unit complexity slack
(2056 vs 2059). This was the 4th such block of the day (diegosouzapw#7695/diegosouzapw#7747/diegosouzapw#7768
each needed helper extraction earlier). Owner approved raising both ceilings
to give new-feature PRs breathing room: complexity to 2072 (combined-cluster
2068 + 4 headroom), cognitive to 900 (combined 896 + 4). Structural shrink
stays debt (diegosouzapw#3501); tighten via --update next cycle.
HouMinXi pushed a commit to HouMinXi/OmniRoute that referenced this pull request Aug 2, 2026
… requests (diegosouzapw#7672)

The provider topology only lit nodes from live/recent traffic, so between
requests (and right after a restart) it went blank even though 50+ connections
were healthy — which reads as "lost providers". Two root causes:

1. Stuck-green latch: request.completed/request.failed are declared in the
   dashboard event map and consumed by useLiveRequests to drain the active-request
   set, but they were never emitted (only request.started was). A node's green
   "active" pulse therefore only cleared on a page reload, and accumulated over a
   session. Emit the terminal event from persistAttemptLogs — keyed by the same
   traceId as request.started — through a pure resolveRequestLifecycleEvent()
   helper (2xx/3xx + no error => completed, else failed).

2. No at-rest state: the map had nothing to show when idle. Colour each node by
   connection health (green connected / red error / grey idle) as a base layer,
   with live/recent traffic still taking precedence and pulsing brighter on top.
   edgeStyle() gains an optional trailing `healthy` param (static dim green) and
   StatusDot a `pulse` prop (static dot for connected-at-rest); both backward
   compatible. Legend "Active" -> "Connected".

Tests: resolveRequestLifecycleEvent success/failure/token-alias units, edgeStyle
healthy variant + precedence, and source guards for the emit wiring (traceId
threaded into persistAttemptLogs) and the health-colour wiring.

Co-authored-by: Diego Rodrigues de Sa e Souza <diegosouza.pw@gmail.com>
Co-authored-by: Diego Rodrigues de Sa e Souza <diegosouzapw@users.noreply.github.com>
muhamadgalihsaputra pushed a commit to niyatna/NiyatnaRoute that referenced this pull request Sep 27, 2026
… (owner-approved)

The /fix-prs validation-train sweep surfaced a cluster of otherwise-clean
contributor feature PRs (diegosouzapw#6973/diegosouzapw#7683/diegosouzapw#7662/diegosouzapw#7672/diegosouzapw#7633/diegosouzapw#7767) whose per-PR
+1/+2 own-growth collectively exceeded the tip's 3-unit complexity slack
(2056 vs 2059). This was the 4th such block of the day (diegosouzapw#7695/diegosouzapw#7747/diegosouzapw#7768
each needed helper extraction earlier). Owner approved raising both ceilings
to give new-feature PRs breathing room: complexity to 2072 (combined-cluster
2068 + 4 headroom), cognitive to 900 (combined 896 + 4). Structural shrink
stays debt (diegosouzapw#3501); tighten via --update next cycle.
muhamadgalihsaputra pushed a commit to niyatna/NiyatnaRoute that referenced this pull request Sep 27, 2026
… requests (diegosouzapw#7672)

The provider topology only lit nodes from live/recent traffic, so between
requests (and right after a restart) it went blank even though 50+ connections
were healthy — which reads as "lost providers". Two root causes:

1. Stuck-green latch: request.completed/request.failed are declared in the
   dashboard event map and consumed by useLiveRequests to drain the active-request
   set, but they were never emitted (only request.started was). A node's green
   "active" pulse therefore only cleared on a page reload, and accumulated over a
   session. Emit the terminal event from persistAttemptLogs — keyed by the same
   traceId as request.started — through a pure resolveRequestLifecycleEvent()
   helper (2xx/3xx + no error => completed, else failed).

2. No at-rest state: the map had nothing to show when idle. Colour each node by
   connection health (green connected / red error / grey idle) as a base layer,
   with live/recent traffic still taking precedence and pulsing brighter on top.
   edgeStyle() gains an optional trailing `healthy` param (static dim green) and
   StatusDot a `pulse` prop (static dot for connected-at-rest); both backward
   compatible. Legend "Active" -> "Connected".

Tests: resolveRequestLifecycleEvent success/failure/token-alias units, edgeStyle
healthy variant + precedence, and source guards for the emit wiring (traceId
threaded into persistAttemptLogs) and the health-colour wiring.

Co-authored-by: Diego Rodrigues de Sa e Souza <diegosouza.pw@gmail.com>
Co-authored-by: Diego Rodrigues de Sa e Souza <diegosouzapw@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants