fix(mcp): separate not-connected from Connected-but-unattached (review 637 B2)
A required namespace absent from the connected-service inventory was never counted as missing, because missing_namespaces was populated only while walking connected_servers. The session therefore reported attachment_healthy true, discovery_status namespaces_attached and error_type None while holding no attachment proof for that namespace, and the gate text told the operator "the host reports Connected" about a service nothing had reported Connected. assess_connected_namespace_attachment now classifies the two conditions apart. missing_namespaces keeps its meaning: required, Connected at the host, absent from the session tool surface -- the actual #708 defect, still typed mcp_connected_namespaces_missing. Required namespaces absent from the connected inventory land in the new not_connected_namespaces list, typed mcp_required_namespaces_not_connected, so a caller is never pointed at an attachment recovery for a service that never connected. attachment_healthy is false whenever any required namespace lacks attachment proof under either condition, error_types reports every condition present so neither hides the other, and namespace_conditions carries the per-namespace connected/attached verdict. Evidence that disagrees with itself -- attached in the session yet absent from the connected inventory -- is reported as contradictory and fails closed rather than being read as proof. attachment_gate_from_session states only what the recorded evidence supports: the Connected wording appears solely when connected is true, the not-connected wording when it is false, and a neutral refusal when connected status was never recorded. Review and merge stay fail-closed in all three cases. _record_live_namespace_attachment consumes the per-namespace verdicts instead of pinning the session-wide error_type onto every unattached namespace and instead of deriving health from a missing list that tracked only one of the two conditions. The two existing cases in test_issue_708_mcp_namespace_attachment.py declared no required_namespaces, so they inherited a default set containing a namespace their connected list omitted. Under the corrected rule that is a false-healthy assertion, so each now declares the required set it actually means. Closes #708 Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
This commit is contained in:
+20
-4
@@ -6731,17 +6731,33 @@ def _record_live_namespace_attachment(assessment: dict | None) -> None:
|
||||
return
|
||||
missing = set(assessment.get("missing_namespaces") or [])
|
||||
error_type = assessment.get("error_type")
|
||||
# Per-namespace verdicts when the assessment supplies them (#708 B2): a session-wide
|
||||
# error_type must never be pinned onto a namespace whose own condition differs, and a
|
||||
# namespace that was never connected must not be recorded healthy just because the
|
||||
# session-wide "missing" list only tracks Connected-but-unattached namespaces.
|
||||
conditions = assessment.get("namespace_conditions")
|
||||
conditions = conditions if isinstance(conditions, dict) else {}
|
||||
for ns, state in proof.items():
|
||||
ns_name = str(ns or "").strip()
|
||||
if not ns_name or not isinstance(state, dict):
|
||||
continue
|
||||
attached = bool(state.get("attached"))
|
||||
condition = conditions.get(ns_name)
|
||||
condition = condition if isinstance(condition, dict) else {}
|
||||
connected = bool(condition.get("connected", state.get("connected")))
|
||||
attached = bool(condition.get("attached", state.get("attached")))
|
||||
if condition:
|
||||
healthy = bool(condition.get("attachment_healthy"))
|
||||
ns_error = condition.get("condition")
|
||||
else:
|
||||
healthy = attached and connected and ns_name not in missing
|
||||
ns_error = None if healthy else error_type
|
||||
_LIVE_NAMESPACE_ATTACHMENT[ns_name] = {
|
||||
"namespace": ns_name,
|
||||
"connected": bool(state.get("connected")),
|
||||
"connected": connected,
|
||||
"attached": attached,
|
||||
"attachment_healthy": attached and ns_name not in missing,
|
||||
"error_type": None if attached else error_type,
|
||||
"attachment_healthy": healthy,
|
||||
"condition": ns_error,
|
||||
"error_type": ns_error,
|
||||
"discovery_status": assessment.get("discovery_status"),
|
||||
"reconnect_required": bool(assessment.get("reconnect_required")),
|
||||
"auto_recovered": bool(assessment.get("auto_recovered")),
|
||||
|
||||
Reference in New Issue
Block a user