From f74c1984d71c99040136688a1e579f30ccfd0957 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?m=C3=BCde?= Date: Mon, 6 Jul 2026 21:48:55 +0200 Subject: [PATCH] =?UTF-8?q?refactor:=20ApprovalKind::as=5Fstr=20owns=20the?= =?UTF-8?q?=20kind=E2=86=92string=20mapping?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit replaces three hand-rolled six-arm matches (actions.rs ×2, state_snapshot.rs); approvals::kind_to_str delegates. a new kind can no longer silently miss one of them --- hive-c0re/src/actions.rs | 18 ++---------------- hive-c0re/src/approvals.rs | 15 ++++----------- hive-c0re/src/dashboard/state_snapshot.rs | 9 +-------- hive-sh4re/src/lib.rs | 18 ++++++++++++++++++ 4 files changed, 25 insertions(+), 35 deletions(-) diff --git a/hive-c0re/src/actions.rs b/hive-c0re/src/actions.rs index e2291c5f..27238df8 100644 --- a/hive-c0re/src/actions.rs +++ b/hive-c0re/src/actions.rs @@ -540,14 +540,7 @@ fn finish_approval( // snapshot refetch. `approved` rows that succeed get the // approval's logged resolved_at indirectly via `now_unix()`; // failures already wrote it via mark_failed above. - let approval_kind = match approval.kind { - ApprovalKind::Spawn => "spawn", - ApprovalKind::ApplyCommit => "apply_commit", - ApprovalKind::InitConfig => "init_config", - ApprovalKind::UpdateMetaInputs => "update_meta_inputs", - ApprovalKind::SchedulePrompt => "schedule_prompt", - ApprovalKind::MergeConfigPr => "merge_config_pr", - }; + let approval_kind = approval.kind.as_str(); let sha_short = approval .fetched_sha .as_deref() @@ -1021,14 +1014,7 @@ pub async fn deny(coord: &Coordinator, id: i64, note: Option<&str>) -> Result<() tracing::warn!(%id, agent = %a.agent, error = ?e, "forge: push_config after deny failed"); } } - let approval_kind = match a.kind { - ApprovalKind::Spawn => "spawn", - ApprovalKind::ApplyCommit => "apply_commit", - ApprovalKind::InitConfig => "init_config", - ApprovalKind::UpdateMetaInputs => "update_meta_inputs", - ApprovalKind::SchedulePrompt => "schedule_prompt", - ApprovalKind::MergeConfigPr => "merge_config_pr", - }; + let approval_kind = a.kind.as_str(); let sha_short = sha.as_deref().map(|s| s[..s.len().min(12)].to_owned()); let description = a.description.clone(); let agent_owned = a.agent.clone(); diff --git a/hive-c0re/src/approvals.rs b/hive-c0re/src/approvals.rs index 8737638f..3b46dc9d 100644 --- a/hive-c0re/src/approvals.rs +++ b/hive-c0re/src/approvals.rs @@ -411,18 +411,11 @@ fn row_to_approval(row: &rusqlite::Row<'_>) -> rusqlite::Result { } /// Stable kind→str mapping used wherever we emit `ApprovalResolved` -/// or persist a kind to sqlite. `pub(crate)` so callers like -/// `questions::handle_cancel_loose_end` don't have to duplicate the -/// match; bumping a kind here is the single source of truth. +/// or persist a kind to sqlite. Thin alias over +/// [`ApprovalKind::as_str`] (the wire-type owns the mapping) kept for +/// the existing call sites' name. pub(crate) fn kind_to_str(kind: ApprovalKind) -> &'static str { - match kind { - ApprovalKind::ApplyCommit => "apply_commit", - ApprovalKind::Spawn => "spawn", - ApprovalKind::InitConfig => "init_config", - ApprovalKind::UpdateMetaInputs => "update_meta_inputs", - ApprovalKind::SchedulePrompt => "schedule_prompt", - ApprovalKind::MergeConfigPr => "merge_config_pr", - } + kind.as_str() } fn kind_from_str(s: &str) -> Result { diff --git a/hive-c0re/src/dashboard/state_snapshot.rs b/hive-c0re/src/dashboard/state_snapshot.rs index aac10c58..e095b242 100644 --- a/hive-c0re/src/dashboard/state_snapshot.rs +++ b/hive-c0re/src/dashboard/state_snapshot.rs @@ -526,14 +526,7 @@ fn history_view(a: Approval) -> ApprovalHistoryView { // Pending shouldn't appear in recent_resolved, but be defensive. hive_sh4re::ApprovalStatus::Pending => "pending", }; - let kind = match a.kind { - hive_sh4re::ApprovalKind::ApplyCommit => "apply_commit", - hive_sh4re::ApprovalKind::Spawn => "spawn", - hive_sh4re::ApprovalKind::InitConfig => "init_config", - hive_sh4re::ApprovalKind::UpdateMetaInputs => "update_meta_inputs", - hive_sh4re::ApprovalKind::SchedulePrompt => "schedule_prompt", - hive_sh4re::ApprovalKind::MergeConfigPr => "merge_config_pr", - }; + let kind = a.kind.as_str(); ApprovalHistoryView { id: a.id, agent: a.agent, diff --git a/hive-sh4re/src/lib.rs b/hive-sh4re/src/lib.rs index a9f1d540..3561ee0f 100644 --- a/hive-sh4re/src/lib.rs +++ b/hive-sh4re/src/lib.rs @@ -250,6 +250,24 @@ pub enum ApprovalKind { MergeConfigPr, } +impl ApprovalKind { + /// Wire/UI string — the same value serde's `snake_case` rename + /// produces. The single source of truth for every place that needs + /// the kind as a `&'static str` (sqlite storage, dashboard events), + /// so adding a variant can't silently miss a hand-rolled match. + #[must_use] + pub fn as_str(self) -> &'static str { + match self { + ApprovalKind::ApplyCommit => "apply_commit", + ApprovalKind::Spawn => "spawn", + ApprovalKind::InitConfig => "init_config", + ApprovalKind::UpdateMetaInputs => "update_meta_inputs", + ApprovalKind::SchedulePrompt => "schedule_prompt", + ApprovalKind::MergeConfigPr => "merge_config_pr", + } + } +} + #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] #[serde(rename_all = "snake_case")] pub enum ApprovalStatus {