diff --git a/lib/crates/fabro-cli/src/commands/run/attach.rs b/lib/crates/fabro-cli/src/commands/run/attach.rs index e682bb519..89a888401 100644 --- a/lib/crates/fabro-cli/src/commands/run/attach.rs +++ b/lib/crates/fabro-cli/src/commands/run/attach.rs @@ -245,7 +245,7 @@ fn api_question_to_question(question: &types::ApiQuestion) -> Question { types::QuestionType::Confirmation => QuestionType::Confirmation, }; let mut converted = Question::new(question.text.clone(), question_type); - converted.id = question.id.clone(); + converted.id.clone_from(&question.id); converted.options = question .options .iter() @@ -255,9 +255,11 @@ fn api_question_to_question(question: &types::ApiQuestion) -> Question { }) .collect(); converted.allow_freeform = question.allow_freeform; - converted.stage = question.stage.clone(); + converted.stage.clone_from(&question.stage); converted.timeout_seconds = question.timeout_seconds; - converted.context_display = question.context_display.clone(); + converted + .context_display + .clone_from(&question.context_display); converted } diff --git a/lib/crates/fabro-cli/src/commands/run/runner.rs b/lib/crates/fabro-cli/src/commands/run/runner.rs index f6d39c36b..fb73265a2 100644 --- a/lib/crates/fabro-cli/src/commands/run/runner.rs +++ b/lib/crates/fabro-cli/src/commands/run/runner.rs @@ -116,14 +116,11 @@ where { let mut lines = BufReader::new(reader).lines(); loop { - match lines.next_line().await { - Ok(Some(line)) => { - apply_worker_control_line(&broker, &line).await; - } - Ok(None) | Err(_) => { - broker.abort_all().await; - break; - } + if let Ok(Some(line)) = lines.next_line().await { + apply_worker_control_line(&broker, &line).await; + } else { + broker.abort_all().await; + break; } } } diff --git a/lib/crates/fabro-server/src/server.rs b/lib/crates/fabro-server/src/server.rs index 4d1094bc9..e38a79878 100644 --- a/lib/crates/fabro-server/src/server.rs +++ b/lib/crates/fabro-server/src/server.rs @@ -58,7 +58,7 @@ use tokio::sync::broadcast::error::RecvError; use tokio::sync::mpsc; use tokio::sync::oneshot; use tokio::task::spawn_blocking; -use tokio::time::sleep; +use tokio::time::{sleep, timeout}; use tokio_stream::StreamExt; use tokio_stream::wrappers::{BroadcastStream, UnboundedReceiverStream}; use tower::{ServiceExt, service_fn}; @@ -331,7 +331,7 @@ impl RunAnswerTransport { match self { Self::Subprocess { control_tx } => { let message = WorkerControlEnvelope::interview_answer(qid.to_string(), answer); - tokio::time::timeout(WORKER_CONTROL_ENQUEUE_TIMEOUT, control_tx.send(message)) + timeout(WORKER_CONTROL_ENQUEUE_TIMEOUT, control_tx.send(message)) .await .map_err(|_| AnswerTransportError::Timeout)? .map_err(|_| AnswerTransportError::Closed) @@ -491,16 +491,15 @@ impl SlackService { } async fn submit_answer(&self, state: Arc, submission: SlackAnswerSubmission) { - let run_id = match RunId::from_str(&submission.run_id) { - Ok(run_id) => run_id, - Err(_) => return, + let Ok(run_id) = RunId::from_str(&submission.run_id) else { + return; }; - let question = - match load_pending_interview_question(state.as_ref(), run_id, &submission.qid).await { - Ok(question) => question, - Err(_) => return, - }; + let Ok(question) = + load_pending_interview_question(state.as_ref(), run_id, &submission.qid).await + else { + return; + }; if validate_answer_for_question(&question, &submission.answer).is_err() { return; } @@ -2910,7 +2909,6 @@ fn parse_question_type(question_type: &str) -> QuestionType { "yes_no" => QuestionType::YesNo, "multiple_choice" => QuestionType::MultipleChoice, "multi_select" => QuestionType::MultiSelect, - "freeform" => QuestionType::Freeform, "confirmation" => QuestionType::Confirmation, _ => QuestionType::Freeform, } @@ -2984,11 +2982,16 @@ async fn load_pending_interview_question( #[allow(clippy::result_large_err)] // Axum handlers naturally propagate full `Response` errors. fn validate_answer_for_question(question: &Question, answer: &Answer) -> Result<(), Response> { match (&question.question_type, &answer.value) { - (QuestionType::YesNo | QuestionType::Confirmation, fabro_interview::AnswerValue::Yes) - | (QuestionType::YesNo | QuestionType::Confirmation, fabro_interview::AnswerValue::No) - | (_, fabro_interview::AnswerValue::Aborted) - | (_, fabro_interview::AnswerValue::Skipped) - | (_, fabro_interview::AnswerValue::Timeout) => Ok(()), + ( + QuestionType::YesNo | QuestionType::Confirmation, + fabro_interview::AnswerValue::Yes | fabro_interview::AnswerValue::No, + ) + | ( + _, + fabro_interview::AnswerValue::Aborted + | fabro_interview::AnswerValue::Skipped + | fabro_interview::AnswerValue::Timeout, + ) => Ok(()), (QuestionType::MultipleChoice, fabro_interview::AnswerValue::Selected(key)) => { if question.options.iter().any(|option| option.key == *key) { Ok(()) @@ -3046,16 +3049,15 @@ async fn deliver_answer_to_run( } }; - match transport.submit(qid, answer).await { - Ok(()) => Ok(()), - Err(_) => { - release_run_answer_claim(state, run_id, qid); - Err(ApiError::new( - StatusCode::SERVICE_UNAVAILABLE, - "Failed to deliver answer to the active run.", - ) - .into_response()) - } + if let Ok(()) = transport.submit(qid, answer).await { + Ok(()) + } else { + release_run_answer_claim(state, run_id, qid); + Err(ApiError::new( + StatusCode::SERVICE_UNAVAILABLE, + "Failed to deliver answer to the active run.", + ) + .into_response()) } } diff --git a/lib/crates/fabro-slack/src/interaction.rs b/lib/crates/fabro-slack/src/interaction.rs index 6d8acdc1c..8aa82fb84 100644 --- a/lib/crates/fabro-slack/src/interaction.rs +++ b/lib/crates/fabro-slack/src/interaction.rs @@ -40,7 +40,6 @@ pub fn parse_interaction(payload: &Value) -> Option { // Ignore checkbox toggle events — wait for Submit button return None; } - "plain_text_input" => return None, _ => return None, }; diff --git a/lib/crates/fabro-workflow/src/handler/human.rs b/lib/crates/fabro-workflow/src/handler/human.rs index 68845b159..49832a9b3 100644 --- a/lib/crates/fabro-workflow/src/handler/human.rs +++ b/lib/crates/fabro-workflow/src/handler/human.rs @@ -13,6 +13,7 @@ use crate::millis_u64; use crate::outcome::{Outcome, OutcomeExt}; use fabro_graphviz::graph::{Graph, Node}; use fabro_interview::{Answer, AnswerValue, Interviewer, Question, QuestionOption, QuestionType}; +use fabro_types::run_event::InterviewOption; use ulid::Ulid; use super::{EngineServices, Handler}; @@ -218,7 +219,7 @@ impl Handler for HumanHandler { options: question .options .iter() - .map(|option| fabro_types::run_event::InterviewOption { + .map(|option| InterviewOption { key: option.key.clone(), label: option.label.clone(), })