Repository: vespa-engine/vespa
File: configserver/src/main/java/com/yahoo/vespa/config/server/modelfactory/PreparedModelsBuilder.java (Java)

Code before:

    private Optional<Model> modelOf(Version version) {
        if (activeApplicationVersions.isEmpty()) return Optional.empty();
        return activeApplicationVersions.get().get(version).map(Application::getModel);
    }

    private HostProvisioner createHostProvisioner(ApplicationPackage applicationPackage, Provisioned provisioned) {
        // Note: nodeRepositoryProvisioner will always be present when hosted is true
        Optional<HostProvisioner> nodeRepositoryProvisioner = createNodeRepositoryProvisioner(params.getApplicationId(), provisioned);
        Optional<AllocatedHosts> allocatedHosts = applicationPackage.getAllocatedHosts();

        if (hosted) {
            // In hosted Vespa, always use node repository provisioner - never read hosts.xml
            if (allocatedHosts.isEmpty()) return nodeRepositoryProvisioner.get();
            // Nodes are already allocated by a model, and we should use them unless this model requests hosts from a
            // previously unallocated cluster. This allows future models to stop allocate certain clusters.
            return createStaticProvisionerForHosted(allocatedHosts.get(), nodeRepositoryProvisioner.get());
        }

        // Non-hosted: use nodeRepositoryProvisioner if available, otherwise fall back to hosts.xml
        if (allocatedHosts.isEmpty() && nodeRepositoryProvisioner.isPresent()) {
            return nodeRepositoryProvisioner.get();
        }

        HostProvisioner defaultHostProvisioner = DeployState.getDefaultModelHostProvisioner(applicationPackage);
        return defaultHostProvisioner;
    }

    private Optional<File> getAppDir(ApplicationPackage applicationPackage) {
        return applicationPackage instanceof FilesApplicationPackage ?
                       Optional.of(((FilesApplicationPackage) applicationPackage).getAppDir()) :
                       Optional.empty();
    }

    private void validateModelHosts(HostValidator hostValidator, ApplicationId applicationId, Model model) {
        // Will retry here, since hosts used might not be in sync on all config servers (we wait for 2/3 servers
        // to respond to deployments and deletions).
        Instant end = Instant.now().plus(Duration.ofSeconds(1));
        IllegalArgumentException exception;
        do {
            try {
                hostValidator.verifyHosts(applicationId, model.getHosts().stream()
                                                              .map(HostInfo::getHostname)
                                                              .toList());
                return;
            } catch (IllegalArgumentException e) {
                exception = e;
                log.log(Level.INFO, "Verifying hosts failed, will retry: " + e.getMessage());
                try {
                    Thread.sleep(100);
                } catch (InterruptedException interruptedException) {/* ignore */}

Review comment (suggestion):
```suggestion
        return DeployState.getDefaultModelHostProvisioner(applicationPackage);
```

Code after:

    private Optional<Model> modelOf(Version version) {
        if (activeApplicationVersions.isEmpty()) return Optional.empty();
        return activeApplicationVersions.get().get(version).map(Application::getModel);
    }

    private HostProvisioner createHostProvisioner(ApplicationPackage applicationPackage, Provisioned provisioned) {
        // Note: nodeRepositoryProvisioner will always be present when hosted is true
        Optional<HostProvisioner> nodeRepositoryProvisioner = createNodeRepositoryProvisioner(params.getApplicationId(), provisioned);
        Optional<AllocatedHosts> allocatedHosts = applicationPackage.getAllocatedHosts();

        if (hosted) {
            // In hosted Vespa, always use node repository provisioner - never read hosts.xml
            if (allocatedHosts.isEmpty()) return nodeRepositoryProvisioner.get();
            // Nodes are already allocated by a model, and we should use them unless this model requests hosts from a
            // previously unallocated cluster. This allows future models to stop allocate certain clusters.
            return createStaticProvisionerForHosted(allocatedHosts.get(), nodeRepositoryProvisioner.get());
        }

        // Non-hosted: use nodeRepositoryProvisioner if available, otherwise fall back to hosts.xml
        if (allocatedHosts.isEmpty() && nodeRepositoryProvisioner.isPresent()) {
            return nodeRepositoryProvisioner.get();
        }

        return DeployState.getDefaultModelHostProvisioner(applicationPackage);
    }

    private Optional<File> getAppDir(ApplicationPackage applicationPackage) {
        return applicationPackage instanceof FilesApplicationPackage ?
                       Optional.of(((FilesApplicationPackage) applicationPackage).getAppDir()) :
                       Optional.empty();
    }

    private void validateModelHosts(HostValidator hostValidator, ApplicationId applicationId, Model model) {
        // Will retry here, since hosts used might not be in sync on all config servers (we wait for 2/3 servers
        // to respond to deployments and deletions).
        Instant end = Instant.now().plus(Duration.ofSeconds(1));
        IllegalArgumentException exception;
        do {
            try {
                hostValidator.verifyHosts(applicationId, model.getHosts().stream()
                                                              .map(HostInfo::getHostname)
                                                              .toList());
                return;
            } catch (IllegalArgumentException e) {
                exception = e;
                log.log(Level.INFO, "Verifying hosts failed, will retry: " + e.getMessage());
                try {
                    Thread.sleep(100);
                } catch (InterruptedException interruptedException) {/* ignore */}
            }