review(Driver.Galaxy.Browser): fix mis-shifted MapSecurityClass codes (High)

Review at HEAD 7286d320. Driver.Galaxy.Browser-001 (High): MapSecurityClass codes 2-6 were
all shifted vs the runtime SecurityClassification enum (wrong security labels in the picker)
-> corrected all 7 arms + tests. -002: DisposeAsync swallows concurrent ObjectDisposedException.
-003 (ResolveApiKey dup) deferred to Contracts.
This commit is contained in:
Joseph Doherty
2026-06-19 10:52:23 -04:00
parent 3c908f1df0
commit 960d76ffcb
3 changed files with 236 additions and 7 deletions
@@ -146,28 +146,42 @@ internal sealed class GalaxyBrowseSession : IBrowseSession
/// <summary>
/// Maps the Galaxy raw security-classification integer to a display string.
/// Buckets: 0=FreeAccess, 1=Operate, 2=Tune, 3=Configure, 4=ViewOnly;
/// anything else surfaces as <c>Unknown(N)</c>.
/// Matches the <c>SecurityClassification</c> enum ordinals and the runtime
/// <c>SecurityMap</c> in Driver.Galaxy:
/// 0=FreeAccess, 1=Operate, 2=SecuredWrite, 3=VerifiedWrite,
/// 4=Tune, 5=Configure, 6=ViewOnly; anything else surfaces as <c>Unknown(N)</c>.
/// </summary>
private static string MapSecurityClass(int raw) => raw switch
// internal for unit-test access (InternalsVisibleTo on the src project).
internal static string MapSecurityClass(int raw) => raw switch
{
0 => "FreeAccess",
1 => "Operate",
2 => "Tune",
3 => "Configure",
4 => "ViewOnly",
2 => "SecuredWrite",
3 => "VerifiedWrite",
4 => "Tune",
5 => "Configure",
6 => "ViewOnly",
_ => $"Unknown({raw})",
};
/// <summary>
/// Idempotently tears down the underlying repository client. Swallows exceptions
/// on shutdown — the registry's reaper may be racing a client-initiated close.
/// Both <see cref="SemaphoreSlim.Dispose"/> and the client dispose are wrapped
/// in try/catch so a concurrent second dispose call never propagates.
/// </summary>
public async ValueTask DisposeAsync()
{
if (_disposed) return;
_disposed = true;
_rootGate.Dispose();
try
{
_rootGate.Dispose();
}
catch (ObjectDisposedException)
{
// Concurrent DisposeAsync caller already disposed the gate — safe to ignore.
}
try
{
await _client.DisposeAsync().ConfigureAwait(false);