Skip to content

[Repo Assist] refactor — eliminate ToLowerInvariant allocations in ChannelHealth; use TryGetValue in UpdateTrackedSession#118

Merged
shanselman merged 1 commit intomasterfrom
repo-assist/improve-channel-health-status-lookup-a0a1ffea71f4d100
Apr 1, 2026
Merged

[Repo Assist] refactor — eliminate ToLowerInvariant allocations in ChannelHealth; use TryGetValue in UpdateTrackedSession#118
shanselman merged 1 commit intomasterfrom
repo-assist/improve-channel-health-status-lookup-a0a1ffea71f4d100

Conversation

@github-actions
Copy link
Copy Markdown
Contributor

🤖 This is an automated PR from Repo Assist.

Summary

Two small, targeted refactors in Models.cs and OpenClawGatewayClient.cs:

1. ChannelHealth.IsHealthyStatus / IsIntermediateStatus — no more ToLowerInvariant allocation

Before:

public static bool IsHealthyStatus(string? status) =>
    status?.ToLowerInvariant() is "ok" or "connected" or "running" or "active" or "ready";

ToLowerInvariant() allocates a new string on every call. Both methods are invoked on every tray menu render cycle (once per channel via MenuDisplayHelper.GetChannelStatusIcon).

After:

private static readonly HashSet(string) s_healthyStatuses =
    new(StringComparer.OrdinalIgnoreCase) { "ok", "connected", "running", "active", "ready" };

public static bool IsHealthyStatus(string? status) =>
    status is not null && s_healthyStatuses.Contains(status);
  • Zero allocation per callHashSet.Contains with OrdinalIgnoreCase comparer does case-insensitive lookup without materialising a new string
  • Same semantics — all existing tests pass unchanged

Consistent with the existing approach in the codebase (see PR #101 eliminating ToLowerInvariant in ClassifyByKeywords, PR #105 using FrozenDictionary in NotificationCategorizer).


2. UpdateTrackedSessionTryGetValue instead of ContainsKey + double-indexer

Before:

if (!_sessions.ContainsKey(sessionKey))
{
    _sessions[sessionKey] = new SessionInfo { ... };
}
_sessions[sessionKey].CurrentActivity = currentActivity;
_sessions[sessionKey].LastSeen = DateTime.UtcNow;

Three to four dictionary lookups for every call.

After:

if (!_sessions.TryGetValue(sessionKey, out var session))
{
    session = new SessionInfo { ... };
    _sessions[sessionKey] = session;
}
session.CurrentActivity = currentActivity;
session.LastSeen = DateTime.UtcNow;
  • Two lookups (one for get-or-create, one insert if new)
  • Local variable avoids repeated hash computation for the property updates
  • Idiomatic C# — standard "get or add" pattern

Test Status

  • dotnet test tests/OpenClaw.Shared.Tests/503 passed, 18 skipped
  • dotnet test tests/OpenClaw.Tray.Tests/93 passed

All existing ChannelHealth.IsHealthyStatus / IsIntermediateStatus tests in ModelsTests.cs pass, confirming identical behaviour.

Generated by Repo Assist ·

To install this agentic workflow, run

gh aw add githubnext/agentics/workflows/repo-assist.md@cbb46ab386962aa371045839fc9998ee4e97ca64

…e TryGetValue in UpdateTrackedSession

ChannelHealth.IsHealthyStatus and IsIntermediateStatus each called
ToLowerInvariant() on every invocation, allocating a new string for every
tray menu refresh cycle. Replace with static HashSet<string> fields using
StringComparer.OrdinalIgnoreCase — O(1) lookup, zero allocation per call.

UpdateTrackedSession used ContainsKey + two separate indexer accesses
(3–4 dict lookups). Replace with TryGetValue + local variable (2 dict
lookups) — idiomatic C# that also avoids repeated hash computation.

503 + 93 tests pass.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@shanselman shanselman marked this pull request as ready for review April 1, 2026 06:44
@shanselman shanselman merged commit cfe9e1f into master Apr 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant