ARCH: прикрепить debug MCP discovery

This commit is contained in:
dctouch 2026-04-20 11:43:40 +03:00
parent 76db8ef012
commit 75e665e836
11 changed files with 352 additions and 7 deletions

View File

@ -891,6 +891,36 @@ Validation:
- `npm test -- assistantMcpDiscoveryRuntimeEntryPoint.test.ts assistantMcpDiscoveryTurnInputAdapter.test.ts assistantMcpDiscoveryPolicy.test.ts assistantMcpCatalogIndex.test.ts assistantMcpDiscoveryPlanner.test.ts assistantMcpDiscoveryRuntimeAdapter.test.ts assistantMcpDiscoveryPilotExecutor.test.ts assistantMcpDiscoveryAnswerAdapter.test.ts assistantMcpDiscoveryRuntimeBridge.test.ts` passed 40/40;
- `npm run build` passed.
## Progress Update - 2026-04-20 MCP Discovery Debug Attachment
The tenth implementation slice of Big Block 5 added a debug/evidence attachment layer:
- `assistantMcpDiscoveryDebugAttachment.ts`
- `assistantMcpDiscoveryDebugAttachment.test.ts`
It is now attached to:
- address-lane response runtime debug;
- deep-analysis debug payloads.
This still does not execute MCP discovery automatically and still does not change the user-facing answer.
It gives runtime and replay review a stable observable surface:
- `assistant_mcp_discovery_entry_point_v1`;
- `mcp_discovery_entry_status`;
- `mcp_discovery_attempted`;
- `mcp_discovery_hot_runtime_wired=false`;
- `mcp_discovery_bridge_status`;
- `mcp_discovery_answer_mode`;
- business-fact/user-facing authorization flags;
- clarification flag.
Validation:
- `npm test -- assistantMcpDiscoveryDebugAttachment.test.ts assistantDebugPayloadAssembler.test.ts assistantAddressLaneResponseRuntimeAdapter.test.ts assistantMcpDiscoveryRuntimeEntryPoint.test.ts` passed 13/13;
- `npm run build` passed.
## Execution Rule
Do not implement this plan as:

View File

@ -4,6 +4,7 @@ exports.runAssistantAddressLaneResponseRuntime = runAssistantAddressLaneResponse
const assistantAddressTurnFinalizeRuntimeAdapter_1 = require("./assistantAddressTurnFinalizeRuntimeAdapter");
const assistantCapabilityBindingResponseGuard_1 = require("./assistantCapabilityBindingResponseGuard");
const assistantCapabilityRuntimeBindingAdapter_1 = require("./assistantCapabilityRuntimeBindingAdapter");
const assistantMcpDiscoveryDebugAttachment_1 = require("./assistantMcpDiscoveryDebugAttachment");
const assistantRuntimeContractResolver_1 = require("./assistantRuntimeContractResolver");
const assistantStateTransitionRuntimeAdapter_1 = require("./assistantStateTransitionRuntimeAdapter");
const assistantTruthAnswerPolicyRuntimeAdapter_1 = require("./assistantTruthAnswerPolicyRuntimeAdapter");
@ -208,13 +209,16 @@ function runAssistantAddressLaneResponseRuntime(input) {
addressRuntimeMeta: input.llmPreDecomposeMeta,
replyType: normalizeAddressReplyType(input.addressLane.reply_type)
});
const debugWithMcpDiscovery = (0, assistantMcpDiscoveryDebugAttachment_1.attachAssistantMcpDiscoveryDebug)(debugWithCapabilityBinding, {
addressRuntimeMeta: input.llmPreDecomposeMeta
});
const guardedResponse = (0, assistantCapabilityBindingResponseGuard_1.applyAssistantCapabilityBindingResponseGuard)({
assistantReply: safeAddressReply,
replyType: normalizeAddressReplyType(input.addressLane.reply_type),
capabilityBinding: debugWithCapabilityBinding.assistant_capability_binding_v1
capabilityBinding: debugWithMcpDiscovery.assistant_capability_binding_v1
});
const debugWithResponseGuard = {
...debugWithCapabilityBinding,
...debugWithMcpDiscovery,
capability_binding_response_guard: guardedResponse.audit
};
const finalization = finalizeAddressTurnSafe({

View File

@ -5,6 +5,7 @@ exports.buildAssistantBackendErrorDebugPayload = buildAssistantBackendErrorDebug
exports.buildAddressRuntimeDebugPayload = buildAddressRuntimeDebugPayload;
exports.buildDeepAnalysisDebugPayload = buildDeepAnalysisDebugPayload;
const assistantCapabilityRuntimeBindingAdapter_1 = require("./assistantCapabilityRuntimeBindingAdapter");
const assistantMcpDiscoveryDebugAttachment_1 = require("./assistantMcpDiscoveryDebugAttachment");
const assistantRuntimeContractResolver_1 = require("./assistantRuntimeContractResolver");
const assistantStateTransitionRuntimeAdapter_1 = require("./assistantStateTransitionRuntimeAdapter");
const assistantTruthAnswerPolicyRuntimeAdapter_1 = require("./assistantTruthAnswerPolicyRuntimeAdapter");
@ -240,6 +241,7 @@ function buildDeepAnalysisDebugPayload(input) {
address_llm_predecompose_contract: input.addressRuntimeMetaForDeep?.predecomposeContract ?? null,
address_semantic_extraction_contract: input.addressRuntimeMetaForDeep?.semanticExtractionContract ?? null,
orchestration_contract_v1: input.addressRuntimeMetaForDeep?.orchestrationContract ?? null,
assistant_mcp_discovery_entry_point_v1: input.addressRuntimeMetaForDeep?.mcpDiscoveryRuntimeEntryPoint ?? null,
assistant_outcome_class_v1: input.outcomeClassV1,
assistant_orchestration_contracts_v1: input.assistantOrchestrationContractsV1,
answer_contract_stage4_v1: answerContractStage4Audit,
@ -263,10 +265,13 @@ function buildDeepAnalysisDebugPayload(input) {
coverageReport: input.coverageReport,
replyType: "deep_analysis"
});
return (0, assistantCapabilityRuntimeBindingAdapter_1.attachAssistantCapabilityRuntimeBinding)(debugWithStateTransition, {
const debugWithCapabilityBinding = (0, assistantCapabilityRuntimeBindingAdapter_1.attachAssistantCapabilityRuntimeBinding)(debugWithStateTransition, {
addressRuntimeMeta: input.addressRuntimeMetaForDeep,
groundingStatus: input.groundingCheck.status,
coverageReport: input.coverageReport,
replyType: "deep_analysis"
});
return (0, assistantMcpDiscoveryDebugAttachment_1.attachAssistantMcpDiscoveryDebug)(debugWithCapabilityBinding, {
addressRuntimeMeta: input.addressRuntimeMetaForDeep
});
}

View File

@ -0,0 +1,53 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.buildAssistantMcpDiscoveryDebugAttachmentFields = buildAssistantMcpDiscoveryDebugAttachmentFields;
exports.attachAssistantMcpDiscoveryDebug = attachAssistantMcpDiscoveryDebug;
function toRecordObject(value) {
if (!value || typeof value !== "object" || Array.isArray(value)) {
return null;
}
return value;
}
function toNonEmptyString(value) {
if (value === null || value === undefined) {
return null;
}
const text = String(value).trim();
return text.length > 0 ? text : null;
}
function isMcpDiscoveryEntryPointContract(value) {
const record = toRecordObject(value);
return (record?.schema_version === "assistant_mcp_discovery_runtime_entry_point_v1" &&
record?.policy_owner === "assistantMcpDiscoveryRuntimeEntryPoint");
}
function resolveEntryPoint(input) {
if (isMcpDiscoveryEntryPointContract(input.entryPoint)) {
return input.entryPoint;
}
const runtimeMetaEntryPoint = input.addressRuntimeMeta?.mcpDiscoveryRuntimeEntryPoint ??
input.addressRuntimeMeta?.assistantMcpDiscoveryRuntimeEntryPoint ??
input.addressRuntimeMeta?.assistant_mcp_discovery_entry_point_v1;
return isMcpDiscoveryEntryPointContract(runtimeMetaEntryPoint) ? runtimeMetaEntryPoint : null;
}
function buildAssistantMcpDiscoveryDebugAttachmentFields(input) {
const entryPoint = resolveEntryPoint(input);
const bridge = toRecordObject(entryPoint?.bridge);
const answerDraft = toRecordObject(bridge?.answer_draft);
return {
assistant_mcp_discovery_entry_point_v1: entryPoint,
mcp_discovery_entry_status: toNonEmptyString(entryPoint?.entry_status),
mcp_discovery_attempted: Boolean(entryPoint?.discovery_attempted),
mcp_discovery_hot_runtime_wired: false,
mcp_discovery_bridge_status: toNonEmptyString(bridge?.bridge_status),
mcp_discovery_answer_mode: toNonEmptyString(answerDraft?.answer_mode),
mcp_discovery_business_fact_answer_allowed: bridge?.business_fact_answer_allowed === true,
mcp_discovery_user_facing_response_allowed: bridge?.user_facing_response_allowed === true,
mcp_discovery_requires_clarification: bridge?.requires_user_clarification === true
};
}
function attachAssistantMcpDiscoveryDebug(debugPayload, input) {
return {
...debugPayload,
...buildAssistantMcpDiscoveryDebugAttachmentFields(input)
};
}

View File

@ -9,6 +9,7 @@ import {
} from "./assistantAddressTurnFinalizeRuntimeAdapter";
import { applyAssistantCapabilityBindingResponseGuard } from "./assistantCapabilityBindingResponseGuard";
import { attachAssistantCapabilityRuntimeBinding } from "./assistantCapabilityRuntimeBindingAdapter";
import { attachAssistantMcpDiscoveryDebug } from "./assistantMcpDiscoveryDebugAttachment";
import { attachAssistantRuntimeContractShadow } from "./assistantRuntimeContractResolver";
import { attachAssistantStateTransition } from "./assistantStateTransitionRuntimeAdapter";
import { attachAssistantTruthAnswerPolicy } from "./assistantTruthAnswerPolicyRuntimeAdapter";
@ -267,13 +268,16 @@ export function runAssistantAddressLaneResponseRuntime<ResponseType = AssistantM
addressRuntimeMeta: input.llmPreDecomposeMeta,
replyType: normalizeAddressReplyType(input.addressLane.reply_type)
});
const debugWithMcpDiscovery = attachAssistantMcpDiscoveryDebug(debugWithCapabilityBinding, {
addressRuntimeMeta: input.llmPreDecomposeMeta
});
const guardedResponse = applyAssistantCapabilityBindingResponseGuard({
assistantReply: safeAddressReply,
replyType: normalizeAddressReplyType(input.addressLane.reply_type),
capabilityBinding: debugWithCapabilityBinding.assistant_capability_binding_v1
capabilityBinding: debugWithMcpDiscovery.assistant_capability_binding_v1
});
const debugWithResponseGuard = {
...debugWithCapabilityBinding,
...debugWithMcpDiscovery,
capability_binding_response_guard: guardedResponse.audit
};
const finalization = finalizeAddressTurnSafe({

View File

@ -24,6 +24,7 @@ import type {
TemporalGuardAudit
} from "./assistantRuntimeGuards";
import { attachAssistantCapabilityRuntimeBinding } from "./assistantCapabilityRuntimeBindingAdapter";
import { attachAssistantMcpDiscoveryDebug } from "./assistantMcpDiscoveryDebugAttachment";
import { attachAssistantRuntimeContractShadow } from "./assistantRuntimeContractResolver";
import { attachAssistantStateTransition } from "./assistantStateTransitionRuntimeAdapter";
import { attachAssistantTruthAnswerPolicy } from "./assistantTruthAnswerPolicyRuntimeAdapter";
@ -333,6 +334,7 @@ export function buildDeepAnalysisDebugPayload(input: DeepAnalysisDebugPayloadInp
address_llm_predecompose_contract: input.addressRuntimeMetaForDeep?.predecomposeContract ?? null,
address_semantic_extraction_contract: input.addressRuntimeMetaForDeep?.semanticExtractionContract ?? null,
orchestration_contract_v1: input.addressRuntimeMetaForDeep?.orchestrationContract ?? null,
assistant_mcp_discovery_entry_point_v1: input.addressRuntimeMetaForDeep?.mcpDiscoveryRuntimeEntryPoint ?? null,
assistant_outcome_class_v1: input.outcomeClassV1,
assistant_orchestration_contracts_v1: input.assistantOrchestrationContractsV1,
answer_contract_stage4_v1: answerContractStage4Audit,
@ -356,10 +358,13 @@ export function buildDeepAnalysisDebugPayload(input: DeepAnalysisDebugPayloadInp
coverageReport: input.coverageReport as unknown as Record<string, unknown>,
replyType: "deep_analysis"
});
return attachAssistantCapabilityRuntimeBinding(debugWithStateTransition, {
const debugWithCapabilityBinding = attachAssistantCapabilityRuntimeBinding(debugWithStateTransition, {
addressRuntimeMeta: input.addressRuntimeMetaForDeep as unknown as Record<string, unknown> | null | undefined,
groundingStatus: input.groundingCheck.status,
coverageReport: input.coverageReport as unknown as Record<string, unknown>,
replyType: "deep_analysis"
});
return attachAssistantMcpDiscoveryDebug(debugWithCapabilityBinding, {
addressRuntimeMeta: input.addressRuntimeMetaForDeep as unknown as Record<string, unknown> | null | undefined
}) as unknown as AssistantDebugPayload;
}

View File

@ -0,0 +1,82 @@
import type { AssistantMcpDiscoveryRuntimeEntryPointContract } from "./assistantMcpDiscoveryRuntimeEntryPoint";
export interface AssistantMcpDiscoveryDebugAttachmentFields {
assistant_mcp_discovery_entry_point_v1: AssistantMcpDiscoveryRuntimeEntryPointContract | null;
mcp_discovery_entry_status: string | null;
mcp_discovery_attempted: boolean;
mcp_discovery_hot_runtime_wired: false;
mcp_discovery_bridge_status: string | null;
mcp_discovery_answer_mode: string | null;
mcp_discovery_business_fact_answer_allowed: boolean;
mcp_discovery_user_facing_response_allowed: boolean;
mcp_discovery_requires_clarification: boolean;
}
export interface AttachAssistantMcpDiscoveryDebugInput {
entryPoint?: unknown;
addressRuntimeMeta?: Record<string, unknown> | null;
}
function toRecordObject(value: unknown): Record<string, unknown> | null {
if (!value || typeof value !== "object" || Array.isArray(value)) {
return null;
}
return value as Record<string, unknown>;
}
function toNonEmptyString(value: unknown): string | null {
if (value === null || value === undefined) {
return null;
}
const text = String(value).trim();
return text.length > 0 ? text : null;
}
function isMcpDiscoveryEntryPointContract(value: unknown): value is AssistantMcpDiscoveryRuntimeEntryPointContract {
const record = toRecordObject(value);
return (
record?.schema_version === "assistant_mcp_discovery_runtime_entry_point_v1" &&
record?.policy_owner === "assistantMcpDiscoveryRuntimeEntryPoint"
);
}
function resolveEntryPoint(input: AttachAssistantMcpDiscoveryDebugInput): AssistantMcpDiscoveryRuntimeEntryPointContract | null {
if (isMcpDiscoveryEntryPointContract(input.entryPoint)) {
return input.entryPoint;
}
const runtimeMetaEntryPoint =
input.addressRuntimeMeta?.mcpDiscoveryRuntimeEntryPoint ??
input.addressRuntimeMeta?.assistantMcpDiscoveryRuntimeEntryPoint ??
input.addressRuntimeMeta?.assistant_mcp_discovery_entry_point_v1;
return isMcpDiscoveryEntryPointContract(runtimeMetaEntryPoint) ? runtimeMetaEntryPoint : null;
}
export function buildAssistantMcpDiscoveryDebugAttachmentFields(
input: AttachAssistantMcpDiscoveryDebugInput
): AssistantMcpDiscoveryDebugAttachmentFields {
const entryPoint = resolveEntryPoint(input);
const bridge = toRecordObject(entryPoint?.bridge);
const answerDraft = toRecordObject(bridge?.answer_draft);
return {
assistant_mcp_discovery_entry_point_v1: entryPoint,
mcp_discovery_entry_status: toNonEmptyString(entryPoint?.entry_status),
mcp_discovery_attempted: Boolean(entryPoint?.discovery_attempted),
mcp_discovery_hot_runtime_wired: false,
mcp_discovery_bridge_status: toNonEmptyString(bridge?.bridge_status),
mcp_discovery_answer_mode: toNonEmptyString(answerDraft?.answer_mode),
mcp_discovery_business_fact_answer_allowed: bridge?.business_fact_answer_allowed === true,
mcp_discovery_user_facing_response_allowed: bridge?.user_facing_response_allowed === true,
mcp_discovery_requires_clarification: bridge?.requires_user_clarification === true
};
}
export function attachAssistantMcpDiscoveryDebug<T extends Record<string, unknown>>(
debugPayload: T,
input: AttachAssistantMcpDiscoveryDebugInput
): T & AssistantMcpDiscoveryDebugAttachmentFields {
return {
...debugPayload,
...buildAssistantMcpDiscoveryDebugAttachmentFields(input)
};
}

View File

@ -86,6 +86,7 @@ export interface AssistantAddressRuntimeMetaForDeep {
predecomposeContract?: Record<string, unknown> | null;
semanticExtractionContract?: Record<string, unknown> | null;
orchestrationContract?: Record<string, unknown> | null;
mcpDiscoveryRuntimeEntryPoint?: Record<string, unknown> | null;
}
export interface AssistantRequirement {

View File

@ -92,7 +92,72 @@ describe("assistant address lane response runtime adapter", () => {
capability_binding_response_guard: expect.objectContaining({
schema_version: "assistant_capability_binding_response_guard_v1",
applied: false
}),
assistant_mcp_discovery_entry_point_v1: null,
mcp_discovery_attempted: false,
mcp_discovery_hot_runtime_wired: false
})
);
});
it("attaches MCP discovery summary from predecompose runtime meta without changing the reply", () => {
const runtime = runAssistantAddressLaneResponseRuntime({
sessionId: "asst-mcp",
userMessage: "raw",
effectiveAddressUserMessage: "raw",
addressLane: {
handled: true,
reply_text: "answer",
reply_type: "partial_coverage",
debug: {}
},
llmPreDecomposeMeta: {
mcpDiscoveryRuntimeEntryPoint: {
schema_version: "assistant_mcp_discovery_runtime_entry_point_v1",
policy_owner: "assistantMcpDiscoveryRuntimeEntryPoint",
entry_status: "bridge_executed",
hot_runtime_wired: false,
discovery_attempted: true,
turn_input: { adapter_status: "ready" },
bridge: {
bridge_status: "answer_draft_ready",
user_facing_response_allowed: true,
business_fact_answer_allowed: true,
requires_user_clarification: false,
answer_draft: { answer_mode: "confirmed_with_bounded_inference" }
},
reason_codes: ["runtime_entry_point_bridge_executed"]
}
},
knownOrganizations: [],
activeOrganization: null,
sanitizeOutgoingAssistantText: (text) => String(text ?? ""),
buildAddressDebugPayload: () => ({}),
buildAddressFollowupOffer: () => null,
mergeKnownOrganizations: (items) => items,
toNonEmptyString: () => null,
appendItem: () => {},
getSession: () => ({ session_id: "asst-mcp", updated_at: "", items: [], investigation_state: null } as any),
persistSession: () => {},
cloneConversation: (items) => items,
logEvent: () => {},
messageIdFactory: () => "msg-mcp",
finalizeAddressTurn: () => ({
response: {
ok: true
}
})
});
expect(runtime.response).toEqual({ ok: true });
expect(runtime.debug).toEqual(
expect.objectContaining({
mcp_discovery_entry_status: "bridge_executed",
mcp_discovery_attempted: true,
mcp_discovery_bridge_status: "answer_draft_ready",
mcp_discovery_answer_mode: "confirmed_with_bounded_inference",
mcp_discovery_business_fact_answer_allowed: true,
mcp_discovery_hot_runtime_wired: false
})
);
});

View File

@ -154,6 +154,9 @@ describe("assistant debug payload assembler", () => {
binding_action: "observe_only"
})
);
expect(payload.assistant_mcp_discovery_entry_point_v1).toBeNull();
expect(payload.mcp_discovery_attempted).toBe(false);
expect(payload.mcp_discovery_hot_runtime_wired).toBe(false);
});
it("omits optional fields when they are not provided", () => {
@ -188,4 +191,35 @@ describe("assistant debug payload assembler", () => {
expect(payload.answer_contract_stage4_v1?.legacy_blocks_present).toContain("Что сломано");
expect(payload.answer_contract_stage4_v1?.legacy_blocks_present).toContain("Ограничения");
});
it("attaches MCP discovery entry point summary when runtime meta provides it", () => {
const input = baseInput();
input.addressRuntimeMetaForDeep = {
...input.addressRuntimeMetaForDeep,
mcpDiscoveryRuntimeEntryPoint: {
schema_version: "assistant_mcp_discovery_runtime_entry_point_v1",
policy_owner: "assistantMcpDiscoveryRuntimeEntryPoint",
entry_status: "bridge_executed",
hot_runtime_wired: false,
discovery_attempted: true,
turn_input: { adapter_status: "ready" },
bridge: {
bridge_status: "answer_draft_ready",
user_facing_response_allowed: true,
business_fact_answer_allowed: true,
requires_user_clarification: false,
answer_draft: { answer_mode: "confirmed_with_bounded_inference" }
},
reason_codes: ["runtime_entry_point_bridge_executed"]
}
};
const payload = buildDeepAnalysisDebugPayload(input);
expect(payload.mcp_discovery_entry_status).toBe("bridge_executed");
expect(payload.mcp_discovery_attempted).toBe(true);
expect(payload.mcp_discovery_bridge_status).toBe("answer_draft_ready");
expect(payload.mcp_discovery_answer_mode).toBe("confirmed_with_bounded_inference");
expect(payload.mcp_discovery_business_fact_answer_allowed).toBe(true);
});
});

View File

@ -0,0 +1,62 @@
import { describe, expect, it } from "vitest";
import { attachAssistantMcpDiscoveryDebug } from "../src/services/assistantMcpDiscoveryDebugAttachment";
function entryPointContract(overrides: Record<string, unknown> = {}) {
return {
schema_version: "assistant_mcp_discovery_runtime_entry_point_v1",
policy_owner: "assistantMcpDiscoveryRuntimeEntryPoint",
entry_status: "bridge_executed",
hot_runtime_wired: false,
discovery_attempted: true,
turn_input: { adapter_status: "ready" },
bridge: {
bridge_status: "answer_draft_ready",
user_facing_response_allowed: true,
business_fact_answer_allowed: true,
requires_user_clarification: false,
answer_draft: {
answer_mode: "confirmed_with_bounded_inference"
}
},
reason_codes: ["runtime_entry_point_bridge_executed"],
...overrides
};
}
describe("assistant MCP discovery debug attachment", () => {
it("attaches a validated entry point contract and exposes summary flags", () => {
const debug = attachAssistantMcpDiscoveryDebug(
{ trace_id: "trace-1" },
{ addressRuntimeMeta: { mcpDiscoveryRuntimeEntryPoint: entryPointContract() } }
);
expect(debug.assistant_mcp_discovery_entry_point_v1?.schema_version).toBe(
"assistant_mcp_discovery_runtime_entry_point_v1"
);
expect(debug.mcp_discovery_entry_status).toBe("bridge_executed");
expect(debug.mcp_discovery_attempted).toBe(true);
expect(debug.mcp_discovery_hot_runtime_wired).toBe(false);
expect(debug.mcp_discovery_bridge_status).toBe("answer_draft_ready");
expect(debug.mcp_discovery_answer_mode).toBe("confirmed_with_bounded_inference");
expect(debug.mcp_discovery_business_fact_answer_allowed).toBe(true);
expect(debug.mcp_discovery_user_facing_response_allowed).toBe(true);
expect(debug.mcp_discovery_requires_clarification).toBe(false);
});
it("keeps safe null flags when no validated entry point exists", () => {
const debug = attachAssistantMcpDiscoveryDebug(
{ trace_id: "trace-1" },
{ addressRuntimeMeta: { mcpDiscoveryRuntimeEntryPoint: { schema_version: "wrong" } } }
);
expect(debug.assistant_mcp_discovery_entry_point_v1).toBeNull();
expect(debug.mcp_discovery_entry_status).toBeNull();
expect(debug.mcp_discovery_attempted).toBe(false);
expect(debug.mcp_discovery_hot_runtime_wired).toBe(false);
expect(debug.mcp_discovery_bridge_status).toBeNull();
expect(debug.mcp_discovery_answer_mode).toBeNull();
expect(debug.mcp_discovery_business_fact_answer_allowed).toBe(false);
expect(debug.mcp_discovery_user_facing_response_allowed).toBe(false);
expect(debug.mcp_discovery_requires_clarification).toBe(false);
});
});