tandem-server 0.6.3

HTTP server for Tandem engine APIs
// Bug Monitor destination readiness helpers split from part02.rs for the
// touched-file size gate.

fn bug_monitor_destination_readiness(
    config: &BugMonitorConfig,
    status: &BugMonitorStatus,
    servers: &std::collections::HashMap<String, tandem_runtime::McpServer>,
) -> Vec<BugMonitorDestinationReadiness> {
    status
        .destinations
        .iter()
        .map(|destination| {
            let mut missing = Vec::new();
            let mut detail = None;
            let requires_approval =
                config.require_approval_for_new_issues || destination.require_approval;

            if !config.enabled {
                missing.push("Bug Monitor is disabled".to_string());
            }
            if config.paused {
                missing.push("Bug Monitor is paused".to_string());
            }
            if !destination.enabled {
                missing.push("Destination is disabled".to_string());
            }

            let publish_ready = match destination.kind {
                BugMonitorDestinationKind::GithubIssue => {
                    let destination_repo = destination.repo.as_deref().or(config.repo.as_deref());
                    let destination_repo_valid =
                        destination_repo.map(is_valid_owner_repo_slug).unwrap_or(false);
                    if destination_repo.is_none() {
                        missing.push("GitHub repo is missing".to_string());
                    } else if !destination_repo_valid {
                        missing.push("GitHub repo must be in owner/repo format".to_string());
                    }

                    let destination_server_name = destination
                        .mcp_server
                        .as_deref()
                        .or(config.mcp_server.as_deref());
                    let destination_server =
                        destination_server_name.and_then(|name| servers.get(name));
                    if destination_server_name.is_none() {
                        missing.push("MCP server is missing".to_string());
                    } else if destination_server.is_none() {
                        missing.push("MCP server is not configured".to_string());
                    } else if !destination_server
                        .as_ref()
                        .map(|row| row.connected)
                        .unwrap_or(false)
                    {
                        missing.push("MCP server is disconnected".to_string());
                    }

                    if !status.readiness.github_read_ready
                        || !status.readiness.github_write_ready
                    {
                        missing.push("GitHub capabilities are missing".to_string());
                    }

                    config.enabled
                        && !config.paused
                        && destination.enabled
                        && destination_repo_valid
                        && destination_server
                            .as_ref()
                            .map(|row| row.connected)
                            .unwrap_or(false)
                        && status.readiness.github_read_ready
                        && status.readiness.github_write_ready
                }
                _ => {
                    detail = Some(
                        "Destination kind is configured but is not available in this phase"
                            .to_string(),
                    );
                    missing.push("Destination implementation is not available".to_string());
                    false
                }
            };

            BugMonitorDestinationReadiness {
                destination_id: destination.destination_id.clone(),
                kind: destination.kind.clone(),
                enabled: destination.enabled,
                ready: publish_ready,
                publish_ready,
                requires_approval,
                missing,
                detail,
            }
        })
        .collect()
}