diff --git a/docs/architecture.mermaid b/docs/architecture.mermaid
index 91603c944e..4f36c28aac 100644
--- a/docs/architecture.mermaid
+++ b/docs/architecture.mermaid
@@ -75,7 +75,7 @@ graph TD
end
subgraph "Domain Layer"
- DOMAIN["src/domain/
Pure side-effect-free modules
format declarations, Evidence, comparisons, application graphs"]
+ DOMAIN["src/domain/
Pure side-effect-free modules
format declarations, provider selection, Evidence, comparisons, application graphs"]
end
subgraph "Configuration"
diff --git a/src/adb/AdbConfiguration.ts b/src/adb/AdbConfiguration.ts
index 2661dfde27..122e244998 100644
--- a/src/adb/AdbConfiguration.ts
+++ b/src/adb/AdbConfiguration.ts
@@ -13,7 +13,7 @@ import {
execFileOutputFailure,
} from "../process/ExecFileOutput.js";
import type { ProviderAvailability } from "../application/AnalysisProvider.js";
-import type { ProviderRejectionCode } from "../contracts/providerSelection.js";
+import type { ProviderRejectionCode } from "../domain/providerSelection.js";
import { fixedAllowanceOptions } from "../domain/fixedAllowanceRemediation.js";
import type { JsonValue } from "../domain/jsonValue.js";
diff --git a/src/apktool/ApktoolConfiguration.ts b/src/apktool/ApktoolConfiguration.ts
index c50e3af7b1..f6187c3443 100644
--- a/src/apktool/ApktoolConfiguration.ts
+++ b/src/apktool/ApktoolConfiguration.ts
@@ -24,7 +24,7 @@ import {
prepareOwnedCommand,
} from "../process/OwnedCommand.js";
import type { ProviderAvailability } from "../application/AnalysisProvider.js";
-import type { ProviderRejectionCode } from "../contracts/providerSelection.js";
+import type { ProviderRejectionCode } from "../domain/providerSelection.js";
import type { JsonValue } from "../domain/jsonValue.js";
import { parse } from "semver";
import {
diff --git a/src/application/AnalysisProvider.ts b/src/application/AnalysisProvider.ts
index 5a06c5c79b..caafeae4b0 100644
--- a/src/application/AnalysisProvider.ts
+++ b/src/application/AnalysisProvider.ts
@@ -17,7 +17,7 @@ import type {
} from "../domain/evidence.js";
import { jsonValueSchema } from "../domain/jsonValue.js";
import type { ProgressReporter } from "./ProgressReporter.js";
-import type { ProviderRejectionCode } from "../contracts/providerSelection.js";
+import type { ProviderRejectionCode } from "../domain/providerSelection.js";
import type { ProcessLineageObservation } from "../process/ProcessOwnership.js";
import type { ProviderOperationHealth } from "../domain/providerOperationHealth.js";
import {
diff --git a/src/application/ClientRegistrationEnvironment.ts b/src/application/ClientRegistrationEnvironment.ts
index 80498a029a..8a1b84afa7 100644
--- a/src/application/ClientRegistrationEnvironment.ts
+++ b/src/application/ClientRegistrationEnvironment.ts
@@ -18,7 +18,7 @@ import {
} from "../process/snapshotEnvironment.js";
import { dshDocument } from "./DshCordisPatch.js";
import type { McpToolTimeoutInputs } from "../mcpStartupPolicy.js";
-import type { AnalysisProviderSelector } from "../contracts/providerSelection.js";
+import type { AnalysisProviderSelector } from "../domain/providerSelection.js";
export type ProviderRequestBudgetResolver = (
analysisProvider: AnalysisProviderSelector,
diff --git a/src/application/DirectAnalysis.ts b/src/application/DirectAnalysis.ts
index c25d83f95d..521675a124 100644
--- a/src/application/DirectAnalysis.ts
+++ b/src/application/DirectAnalysis.ts
@@ -20,6 +20,7 @@ import { createImmutableEvidenceBundle } from "../domain/evidenceBundle.js";
import { retainAnalysisResultSources } from "./investigation/recordEvidenceSources.js";
import type { Evidence } from "../domain/evidence.js";
import type { NativeToolName } from "../contracts/native/nativeToolContracts.js";
+import type { EnhancedToolName } from "../contracts/enhancedInputs.js";
import {
ARTIFACT_ANALYSIS_OPERATIONS,
type ArtifactAnalysisOperation,
@@ -61,7 +62,7 @@ import {
workflowSnapshotRecord,
recordWorkflowUnknowns,
} from "./WorkflowEvidence.js";
-import type { AnalysisProviderSelector } from "../contracts/providerSelection.js";
+import type { AnalysisProviderSelector } from "../domain/providerSelection.js";
import { resolveXrefsAddress } from "./XrefsAddressResolution.js";
import {
AnalysisCancelledError,
@@ -598,15 +599,7 @@ const executeAnalysisTool = async (input: {
);
return result.ok ? ok({ evidence: result.value }) : result;
}
- if (
- tool === "binary_overview" ||
- tool === "inspect_native_api" ||
- tool === "inspect_native_dispatch_metadata" ||
- tool === "trace_feature" ||
- tool === "trace_native_values" ||
- tool === "trace_native_ui_action" ||
- tool === "decompile_all"
- ) {
+ if (isWorkflowEvidenceTool(tool)) {
const { EnhancedTools } = await import("./EnhancedTools.js");
let result = await executeComposedWorkflow(
session,
@@ -812,7 +805,10 @@ const isWorkflowEvidenceTool = (
| ArtifactAnalysisOperation
| ManagedToolName
| DirectAnalysisTool,
-): boolean =>
+): tool is Exclude<
+ Extract,
+ "analyze_function"
+> =>
tool === "binary_overview" ||
tool === "inspect_native_api" ||
tool === "inspect_native_dispatch_metadata" ||
diff --git a/src/application/SetupHost.ts b/src/application/SetupHost.ts
index 569a0b3d16..60402a7cf4 100644
--- a/src/application/SetupHost.ts
+++ b/src/application/SetupHost.ts
@@ -81,7 +81,7 @@ import {
} from "../artifacts/AnalysisCleanupLease.js";
import { bindRegularFileCleanup } from "./RegularFileRead.js";
import { CURRENT_ENTRYPOINT_PATH } from "../process/CurrentEntrypointPath.js";
-import { analysisProviderSelectorSchema } from "../contracts/providerSelection.js";
+import { analysisProviderSelectorSchema } from "../domain/providerSelection.js";
/** Resolve the executable and arguments used in a managed MCP registration. */
export const setupRegistrationCommand = (
diff --git a/src/application/binary/AnalysisProviderRegistry.ts b/src/application/binary/AnalysisProviderRegistry.ts
index 3af1805679..ba7df2051f 100644
--- a/src/application/binary/AnalysisProviderRegistry.ts
+++ b/src/application/binary/AnalysisProviderRegistry.ts
@@ -11,7 +11,7 @@ import {
analysisProviderIdSchema,
analysisProviderSelectorSchema,
type AnalysisProviderSelector,
-} from "../../contracts/providerSelection.js";
+} from "../../domain/providerSelection.js";
import type { AnalysisProfileCommitment } from "../../domain/analysisProfile.js";
import type { BinaryTarget } from "../../domain/binaryTargetTypes.js";
import {
diff --git a/src/application/binary/BinarySessionOpen.ts b/src/application/binary/BinarySessionOpen.ts
index 75af7bcbc6..1b370b7d6d 100644
--- a/src/application/binary/BinarySessionOpen.ts
+++ b/src/application/binary/BinarySessionOpen.ts
@@ -4,7 +4,7 @@ import type {
BinaryTarget,
} from "../../domain/binaryTargetTypes.js";
import { artifactTargetSelectedPath } from "../../domain/binaryTargetTypes.js";
-import type { AnalysisProviderSelector } from "../../contracts/providerSelection.js";
+import type { AnalysisProviderSelector } from "../../domain/providerSelection.js";
import type { AnalysisProfileCommitment } from "../../domain/analysisProfile.js";
import {
snapshotMatchesBinding,
diff --git a/src/application/binary/BinarySessionPort.ts b/src/application/binary/BinarySessionPort.ts
index b6fe5cdeb3..12e46f26a6 100644
--- a/src/application/binary/BinarySessionPort.ts
+++ b/src/application/binary/BinarySessionPort.ts
@@ -7,7 +7,7 @@ import type {
import type { JsonValue } from "../../domain/jsonValue.js";
import type { AnalysisSnapshot } from "../../domain/analysisSnapshot.js";
import type { AnalysisProfileCommitment } from "../../domain/analysisProfile.js";
-import type { AnalysisProviderSelector } from "../../contracts/providerSelection.js";
+import type { AnalysisProviderSelector } from "../../domain/providerSelection.js";
import type { BinarySessionDetail } from "../../contracts/sessionStatusContract.js";
import type { AnalysisError } from "../../domain/analysisErrorBase.js";
import type { Result } from "../../domain/result.js";
diff --git a/src/application/binary/SessionProviderRouter.ts b/src/application/binary/SessionProviderRouter.ts
index 0989460b4f..5e454bd54c 100644
--- a/src/application/binary/SessionProviderRouter.ts
+++ b/src/application/binary/SessionProviderRouter.ts
@@ -1,4 +1,4 @@
-import type { AnalysisProviderSelector } from "../../contracts/providerSelection.js";
+import type { AnalysisProviderSelector } from "../../domain/providerSelection.js";
import type { AnalysisProfileCommitment } from "../../domain/analysisProfile.js";
import type { BinaryTarget } from "../../domain/binaryTargetTypes.js";
import { AnalysisCapabilityUnavailableError } from "../../domain/analysisErrorCore.js";
diff --git a/src/cli/options.ts b/src/cli/options.ts
index 0ebef6c0fe..2de0d6b1e7 100644
--- a/src/cli/options.ts
+++ b/src/cli/options.ts
@@ -9,8 +9,8 @@ import {
binaryArchitectureSchema,
rawBinaryEntryPointSchema,
} from "../domain/rawBinary.js";
-import { analysisProviderSelectorSchema } from "../contracts/providerSelection.js";
-import type { AnalysisProviderSelector } from "../contracts/providerSelection.js";
+import { analysisProviderSelectorSchema } from "../domain/providerSelection.js";
+import type { AnalysisProviderSelector } from "../domain/providerSelection.js";
import type { Logger } from "pino";
/** Parse decimal integer tokens before Number coercion can erase their syntax. */
diff --git a/src/config/environment.ts b/src/config/environment.ts
index ba19d64982..fbc771dbea 100644
--- a/src/config/environment.ts
+++ b/src/config/environment.ts
@@ -7,7 +7,7 @@ import { isAbsolute } from "node:path";
import { ConfigurationError } from "../domain/configurationErrors.js";
import { err, ok, type Result } from "../domain/result.js";
-import { analysisProviderSelectorSchema } from "../contracts/providerSelection.js";
+import { analysisProviderSelectorSchema } from "../domain/providerSelection.js";
import {
ghidraCompilerSpecIdSchema,
ghidraLanguageIdSchema,
diff --git a/src/config/types.ts b/src/config/types.ts
index e9c85a5703..880b03674b 100644
--- a/src/config/types.ts
+++ b/src/config/types.ts
@@ -2,7 +2,7 @@ import type { GhidraProjectSelection } from "./ghidraExistingProject.js";
import type { McpToolFamilies } from "./mcpToolFamilies.js";
import type { LogLevel } from "./processStart.js";
import type { ReferenceSourcePolicy } from "../domain/referenceSourcePolicy.js";
-import type { AnalysisProviderSelector } from "../contracts/providerSelection.js";
+import type { AnalysisProviderSelector } from "../domain/providerSelection.js";
import type { GhidraLanguageOverride } from "./ghidraLanguageOverride.js";
import type { McpInputSchemaProfile } from "./mcpInputSchemaProfile.js";
diff --git a/src/contracts/sessionLifecycleInputs.ts b/src/contracts/sessionLifecycleInputs.ts
index 48a1182770..b0bb246e80 100644
--- a/src/contracts/sessionLifecycleInputs.ts
+++ b/src/contracts/sessionLifecycleInputs.ts
@@ -6,7 +6,7 @@ import {
rawBinarySelectionError,
} from "../domain/rawBinary.js";
import { z } from "zod";
-import { analysisProviderSelectorSchema } from "./providerSelection.js";
+import { analysisProviderSelectorSchema } from "../domain/providerSelection.js";
/** Caller-supplied analysis snapshot path; must name its destination absolutely. */
const snapshotPathSchema = absoluteLocalPathStringSchema.describe(
diff --git a/src/contracts/toolOutputSchemaPrimitives.ts b/src/contracts/toolOutputSchemaPrimitives.ts
index 3aaa48332a..7c91104297 100644
--- a/src/contracts/toolOutputSchemaPrimitives.ts
+++ b/src/contracts/toolOutputSchemaPrimitives.ts
@@ -12,7 +12,7 @@ import { jsonObjectSchema } from "../domain/jsonValue.js";
import {
PROVIDER_REJECTION_CODES,
type ProviderRejectionCode,
-} from "./providerSelection.js";
+} from "../domain/providerSelection.js";
import {
PROVIDER_FAILURE_STAGES,
PROVIDER_OPERATION_STATES,
diff --git a/src/contracts/providerSelection.ts b/src/domain/providerSelection.ts
similarity index 100%
rename from src/contracts/providerSelection.ts
rename to src/domain/providerSelection.ts
diff --git a/src/ghidra/GhidraInstallation.ts b/src/ghidra/GhidraInstallation.ts
index 46d0c8f092..7f30a7f6a0 100644
--- a/src/ghidra/GhidraInstallation.ts
+++ b/src/ghidra/GhidraInstallation.ts
@@ -22,7 +22,7 @@ import {
import { constants, accessSync, realpathSync, statSync } from "node:fs";
import { delimiter as pathDelimiter, dirname, posix, win32 } from "node:path";
-import type { ProviderRejectionCode } from "../contracts/providerSelection.js";
+import type { ProviderRejectionCode } from "../domain/providerSelection.js";
import {
parseExecutableHeader,
readFatArchitectureFamilies,
diff --git a/src/kuna/KunaProviderCapabilities.ts b/src/kuna/KunaProviderCapabilities.ts
index 3ef7882934..425b5fdf6a 100644
--- a/src/kuna/KunaProviderCapabilities.ts
+++ b/src/kuna/KunaProviderCapabilities.ts
@@ -2,7 +2,7 @@ import type {
AnalysisOperation,
CapabilityDescriptor,
} from "../application/AnalysisProvider.js";
-import type { ProviderRejectionCode } from "../contracts/providerSelection.js";
+import type { ProviderRejectionCode } from "../domain/providerSelection.js";
import { KUNA_PROVIDER_ID } from "./KunaRelease.js";
import {
DEFAULT_REGEX_MATCHING_DEADLINE,
diff --git a/src/mcpStartupPolicy.ts b/src/mcpStartupPolicy.ts
index d9c5f3a9bf..a1a914ce59 100644
--- a/src/mcpStartupPolicy.ts
+++ b/src/mcpStartupPolicy.ts
@@ -1,4 +1,4 @@
-import type { AnalysisProviderSelector } from "./contracts/providerSelection.js";
+import type { AnalysisProviderSelector } from "./domain/providerSelection.js";
import {
mcpPhaseBudgetRecovery,
type McpPhaseBudget,
diff --git a/src/pcap/PcapConfiguration.ts b/src/pcap/PcapConfiguration.ts
index 463cca8e51..5eb33217ac 100644
--- a/src/pcap/PcapConfiguration.ts
+++ b/src/pcap/PcapConfiguration.ts
@@ -4,7 +4,7 @@ import { delimiter, isAbsolute } from "node:path";
import { appendCallerPath } from "../filesystem/callerPath.js";
import type { ProviderAvailability } from "../application/AnalysisProvider.js";
-import type { ProviderRejectionCode } from "../contracts/providerSelection.js";
+import type { ProviderRejectionCode } from "../domain/providerSelection.js";
import type { AnalysisErrorOptions } from "../domain/analysisErrorBase.js";
import {
AnalysisCapabilityUnavailableError,
diff --git a/tests/boundary/mcp/callRelationshipAvailability.test.ts b/tests/boundary/mcp/callRelationshipAvailability.test.ts
index d3c3621a36..97a2ede20d 100644
--- a/tests/boundary/mcp/callRelationshipAvailability.test.ts
+++ b/tests/boundary/mcp/callRelationshipAvailability.test.ts
@@ -11,7 +11,7 @@ import type {
} from "../../../src/application/AnalysisProvider.js";
import { createAnalysisExecution } from "../../../src/application/AnalysisProvider.js";
import { ok } from "../../../src/domain/result.js";
-import type { ProviderRejectionCode } from "../../../src/contracts/providerSelection.js";
+import type { ProviderRejectionCode } from "../../../src/domain/providerSelection.js";
import { toolContract } from "../../../src/contracts/toolContracts.js";
import { expandToolAvailability } from "../../../src/contracts/toolOutputSchemaPrimitives.js";
import { parseMcpToolError } from "../../fixtures/mcpToolError.js";
diff --git a/tests/boundary/mcp/nativeDispatchAvailability.test.ts b/tests/boundary/mcp/nativeDispatchAvailability.test.ts
index 6ba0abae62..5d071237a8 100644
--- a/tests/boundary/mcp/nativeDispatchAvailability.test.ts
+++ b/tests/boundary/mcp/nativeDispatchAvailability.test.ts
@@ -13,7 +13,7 @@ import { createAnalysisExecution } from "../../../src/application/AnalysisProvid
import { AnalysisOutputError } from "../../../src/domain/analysisErrorCore.js";
import { inspectNativeDispatchMetadata } from "../../../src/domain/native/objcSwiftMetadata.js";
import { err, ok } from "../../../src/domain/result.js";
-import type { ProviderRejectionCode } from "../../../src/contracts/providerSelection.js";
+import type { ProviderRejectionCode } from "../../../src/domain/providerSelection.js";
import { toolContract } from "../../../src/contracts/toolContracts.js";
import { expandToolAvailability } from "../../../src/contracts/toolOutputSchemaPrimitives.js";
import { parseMcpToolError } from "../../fixtures/mcpToolError.js";