Skip to content

Handshake count cross-check can compare against an incomplete aggregate #92

Description

@a-effort

HandshakeTestPanel cross-checks the component counts a handshake returns against the virtual server's own aggregate, and shows an amber "Component counts don't match the virtual server's aggregate. This can mean a federated source is unreachable or filtering has diverged" banner on a mismatch.

PR #76 fixed the main population mismatch by excluding disabled components from the aggregate (VirtualServerDetailsPanel.tsx:295-302), since the handshake's list calls only ever see enabled ones. Two narrower paths can still produce a spurious banner.

1. A single failed query silently contributes 0. The aggregate is summed over whichever of the three /servers/{id}/{tools,resources,prompts} queries returned data. If the resources query 403s while tools succeeds, the aggregate records resources: 0 against a handshake reporting 3, and the banner fires.

2. The fallback population can't be filtered. When all three queries come back empty or errored, allComponents falls back to buildComponentItems(server) (:287). Those items are built from the associatedTools / associatedResources / associatedPrompts name lists and carry no enabled field (components/gateways/utils.ts:59-86), so the enabled === false filter can never fire and disabled components get counted again.

Severity: low. The consequence is a false advisory banner. The handshake result, meta line, capability flags and raw response are all unaffected, and nothing destructive follows. Path 1 needs a permission or backend failure on one of the three component queries; path 2 needs all three to fail together.

Suggested fix: pass aggregatedCounts only when all three queries have succeeded, and derive it from fetchedComponents rather than allComponents. useQuery already exposes a per-call error (hooks/useQuery.ts:27), so this is a destructure plus a guard at the call site (:497). HandshakeTestPanel already handles an absent aggregate: hasComparison goes false and the comparison column and banner drop out.

Note that gating on the existing componentsLoading (:344) fixes neither path, since isLoading goes false on error.

Trade-off: a virtual server with genuinely zero components would lose the "matches server's total" confirmation, since an empty fetched population is indistinguishable from a failed one at the call site. Acceptable, or worth tracking success explicitly.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions