From dbe36ae7d205b57c7fca34d6e4c3851401839cc6 Mon Sep 17 00:00:00 2001 From: "Andrei G." Date: Thu, 28 May 2026 21:33:53 +0200 Subject: [PATCH] refactor(memory,common,config,tools,context,orchestration,subagent,acp,a2a,tui,core): add #[non_exhaustive] to extensible pub enums Marks all extensible public enums across the remaining crates as #[non_exhaustive] so that adding new variants in future releases is not a breaking change for downstream crates. Crates covered: zeph-memory, zeph-common, zeph-config, zeph-tools, zeph-agent-context, zeph-context, zeph-orchestration, zeph-subagent, zeph-acp, zeph-a2a, zeph-mcp, zeph-core, zeph-tui, and the root binary (src/). Closes #4513, #4514. --- CHANGELOG.md | 4 +- crates/zeph-a2a/src/error.rs | 1 + crates/zeph-a2a/src/ibct.rs | 1 + crates/zeph-a2a/src/server/state.rs | 2 + crates/zeph-acp/src/agent/mod.rs | 6 +- crates/zeph-agent-context/src/helpers.rs | 3 +- .../zeph-agent-context/src/memory_backend.rs | 6 +- .../src/summarization/pruning.rs | 2 +- .../src/summarization/scheduling.rs | 4 +- crates/zeph-channels/src/any.rs | 1 + crates/zeph-channels/src/line_editor.rs | 1 + crates/zeph-channels/src/telegram_api_ext.rs | 2 + crates/zeph-commands/src/lib.rs | 1 + crates/zeph-common/src/audit.rs | 2 + crates/zeph-common/src/error_taxonomy.rs | 2 + crates/zeph-common/src/memory.rs | 4 + crates/zeph-common/src/policy.rs | 1 + crates/zeph-common/src/secret.rs | 1 + crates/zeph-common/src/task_supervisor.rs | 3 + crates/zeph-common/src/trust_level.rs | 1 + crates/zeph-config/src/agent.rs | 3 + crates/zeph-config/src/autonomous.rs | 1 + crates/zeph-config/src/channels.rs | 3 + crates/zeph-config/src/classifiers.rs | 1 + crates/zeph-config/src/dump_format.rs | 1 + crates/zeph-config/src/error.rs | 1 + crates/zeph-config/src/experiment.rs | 1 + crates/zeph-config/src/features.rs | 2 + crates/zeph-config/src/learning.rs | 1 + crates/zeph-config/src/logging.rs | 1 + crates/zeph-config/src/mcp_security.rs | 2 + crates/zeph-config/src/memory.rs | 14 ++ crates/zeph-config/src/migrate/mod.rs | 1 + crates/zeph-config/src/quality.rs | 1 + crates/zeph-config/src/sanitizer.rs | 2 + crates/zeph-config/src/security.rs | 1 + crates/zeph-config/src/subagent.rs | 4 + crates/zeph-config/src/telemetry.rs | 1 + crates/zeph-config/src/tools.rs | 8 + crates/zeph-config/src/ui.rs | 5 + crates/zeph-context/src/assembler.rs | 4 +- .../agent/context/summarization/adapters.rs | 1 + .../agent/context/summarization/pruning.rs | 2 +- crates/zeph-core/src/agent/log_commands.rs | 2 +- crates/zeph-core/src/agent/mod.rs | 6 +- crates/zeph-core/src/agent/policy_commands.rs | 2 +- .../zeph-core/src/agent/speculative/cache.rs | 3 + crates/zeph-core/src/debug_dump/mod.rs | 2 +- crates/zeph-core/src/lsp_hooks/diagnostics.rs | 2 +- crates/zeph-core/src/quality/config.rs | 2 +- crates/zeph-gateway/src/error.rs | 1 + crates/zeph-mcp/src/manager.rs | 3 +- crates/zeph-memory/src/compaction_probe.rs | 1 + crates/zeph-memory/src/consolidation.rs | 1 + crates/zeph-memory/src/document/error.rs | 1 + crates/zeph-memory/src/embedding_registry.rs | 1 + crates/zeph-memory/src/embedding_store.rs | 1 + crates/zeph-memory/src/error.rs | 1 + crates/zeph-memory/src/facade.rs | 1 + crates/zeph-memory/src/graph/conflict.rs | 1 + crates/zeph-memory/src/graph/ontology.rs | 1 + crates/zeph-memory/src/graph/resolver/mod.rs | 1 + crates/zeph-memory/src/graph/types.rs | 3 +- crates/zeph-memory/src/optical_forgetting.rs | 1 + crates/zeph-memory/src/quality_gate.rs | 1 + crates/zeph-memory/src/reasoning.rs | 1 + crates/zeph-memory/src/semantic/mod.rs | 5 + crates/zeph-memory/src/semantic/recall.rs | 16 +- .../zeph-memory/src/semantic/write_buffer.rs | 1 + crates/zeph-memory/src/shadow/mod.rs | 4 + .../zeph-memory/src/store/agent_sessions.rs | 3 + .../src/store/retrieval_failures.rs | 1 + crates/zeph-memory/src/store/trust.rs | 1 + crates/zeph-memory/src/tiered_retrieval.rs | 3 +- crates/zeph-memory/src/types.rs | 1 + crates/zeph-memory/src/vector_store.rs | 2 + crates/zeph-orchestration/src/dag.rs | 4 + crates/zeph-orchestration/src/plan_cache.rs | 2 +- crates/zeph-orchestration/src/planner.rs | 2 +- crates/zeph-orchestration/src/router.rs | 2 +- crates/zeph-skills/src/scanner.rs | 2 +- crates/zeph-subagent/src/def.rs | 2 +- crates/zeph-subagent/src/filter.rs | 2 +- crates/zeph-subagent/src/hooks.rs | 1 + crates/zeph-subagent/src/manager.rs | 2 +- crates/zeph-subagent/src/memory.rs | 7 + crates/zeph-tools/src/audit.rs | 2 +- crates/zeph-tools/src/executor.rs | 2 +- crates/zeph-tools/src/permissions.rs | 1 + crates/zeph-tools/src/policy.rs | 3 + crates/zeph-tools/src/scope.rs | 2 +- crates/zeph-tools/src/trust_gate.rs | 37 ++-- crates/zeph-tui/src/widgets/fleet.rs | 1 + crates/zeph-tui/src/widgets/memory.rs | 2 + crates/zeph-tui/src/widgets/subagents.rs | 2 +- crates/zeph-tui/src/widgets/task_registry.rs | 2 + src/agent_setup.rs | 2 +- src/bootstrap/mcp.rs | 1 + src/bootstrap/mod.rs | 12 +- src/commands/agents.rs | 1 + src/commands/project.rs | 172 +++++++++--------- src/runner.rs | 19 +- src/scheduler.rs | 1 + src/tracing_init.rs | 2 +- 104 files changed, 319 insertions(+), 156 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 65f830108..49855fdbb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -42,7 +42,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). undocumented public items: `EmbeddingStore::with_store`, `EmbeddingStore::health_check`, `ProviderStats` fields, `EmaTracker::new`, `Extractor::extract`, `CompatibleProvider` builder methods, `MiningConfig` fields (closes #4483). - +- `zeph-memory`, `zeph-common`, `zeph-config`, `zeph-channels`, `zeph-commands`, `zeph-gateway`, + `zeph-a2a`: add `#[non_exhaustive]` to all extensible `pub enum` types — adding new variants + in future releases will not be a breaking change for downstream crates (closes #4513, #4514, #4532). - `zeph-llm`: mark `StreamChunk`, `ThinkingBlock`, `ChatResponse`, `MessagePart`, and `LlmError` as `#[non_exhaustive]` — adding new variants in the future will not be a breaking change for downstream crates (closes #4515, #4517). diff --git a/crates/zeph-a2a/src/error.rs b/crates/zeph-a2a/src/error.rs index d0db8db8d..4c271aae7 100644 --- a/crates/zeph-a2a/src/error.rs +++ b/crates/zeph-a2a/src/error.rs @@ -13,6 +13,7 @@ use crate::jsonrpc::JsonRpcError; /// `-32002` is not-cancelable. /// - Abort on [`Security`](A2aError::Security) — endpoint rejected by TLS or SSRF policy. #[derive(Debug, thiserror::Error)] +#[non_exhaustive] pub enum A2aError { /// A `reqwest` HTTP transport error (connection refused, timeout, TLS, etc.). #[error("HTTP request failed: {0}")] diff --git a/crates/zeph-a2a/src/ibct.rs b/crates/zeph-a2a/src/ibct.rs index 9fab7a781..04b41d141 100644 --- a/crates/zeph-a2a/src/ibct.rs +++ b/crates/zeph-a2a/src/ibct.rs @@ -45,6 +45,7 @@ const CLOCK_SKEW_GRACE_SECS: u64 = 30; /// Errors produced by [`Ibct::issue`] and [`Ibct::verify`]. #[derive(Debug, Error)] +#[non_exhaustive] pub enum IbctError { /// The HMAC-SHA256 signature does not match the token's fields. /// Indicates tampering or use of a wrong key. diff --git a/crates/zeph-a2a/src/server/state.rs b/crates/zeph-a2a/src/server/state.rs index 6b4609587..04be66fd8 100644 --- a/crates/zeph-a2a/src/server/state.rs +++ b/crates/zeph-a2a/src/server/state.rs @@ -39,6 +39,7 @@ pub struct AppState { /// final artifact. [`StatusUpdate`](ProcessorEvent::StatusUpdate) events update the task's /// state in [`TaskManager`] and, for streaming calls, are forwarded as SSE events. #[derive(Debug, Clone)] +#[non_exhaustive] pub enum ProcessorEvent { /// A task lifecycle state transition. Set `is_final = true` on the terminal state. StatusUpdate { state: TaskState, is_final: bool }, @@ -244,6 +245,7 @@ impl Default for TaskManager { /// Error returned by [`TaskManager::cancel_task`] when cancellation cannot proceed. #[derive(Debug)] +#[non_exhaustive] pub enum CancelError { /// No task with the given ID exists in the store. NotFound, diff --git a/crates/zeph-acp/src/agent/mod.rs b/crates/zeph-acp/src/agent/mod.rs index f2770cb17..ccd96c9f9 100644 --- a/crates/zeph-acp/src/agent/mod.rs +++ b/crates/zeph-acp/src/agent/mod.rs @@ -1166,10 +1166,8 @@ impl ZephAcpAgentState { let auth_methods: Vec = self .auth_methods_config .iter() - .map(|m| match m { - zeph_core::config::AcpAuthMethod::Agent => acp::schema::AuthMethod::Agent( - acp::schema::AuthMethodAgent::new("zeph", "Zeph"), - ), + .map(|_m| { + acp::schema::AuthMethod::Agent(acp::schema::AuthMethodAgent::new("zeph", "Zeph")) }) .collect(); diff --git a/crates/zeph-agent-context/src/helpers.rs b/crates/zeph-agent-context/src/helpers.rs index 48a9a0154..9ee18e01a 100644 --- a/crates/zeph-agent-context/src/helpers.rs +++ b/crates/zeph-agent-context/src/helpers.rs @@ -704,6 +704,7 @@ pub async fn fetch_graph_facts_raw( } append_graph_facts(&facts, &mut body, &mut tokens_so_far, budget_tokens, tc); } + _ => {} } if body == GRAPH_FACTS_PREFIX { @@ -802,7 +803,7 @@ pub async fn fetch_semantic_recall_raw( } let entry = match context_format { ContextFormat::Structured => format_structured_recall_entry(item), - ContextFormat::Plain => format_plain_recall_entry(item), + _ => format_plain_recall_entry(item), }; let entry_tokens = tc.count_tokens(&entry); if tokens_used + entry_tokens > token_budget { diff --git a/crates/zeph-agent-context/src/memory_backend.rs b/crates/zeph-agent-context/src/memory_backend.rs index 1222faaf7..8cae09dae 100644 --- a/crates/zeph-agent-context/src/memory_backend.rs +++ b/crates/zeph-agent-context/src/memory_backend.rs @@ -244,9 +244,9 @@ impl ContextMemoryBackend for SemanticMemoryBackend { ) -> BoxFut<'a, Vec> { Box::pin(async move { let mem_view = match params.view { - RecallView::Head => MemRecallView::Head, RecallView::ZoomIn => MemRecallView::ZoomIn, RecallView::ZoomOut => MemRecallView::ZoomOut, + _ => MemRecallView::Head, }; let mem_edge_types: Vec = params .edge_types @@ -255,10 +255,10 @@ impl ContextMemoryBackend for SemanticMemoryBackend { use zeph_common::memory::EdgeType as CE; use zeph_memory::EdgeType as ME; match e { - CE::Semantic => ME::Semantic, CE::Temporal => ME::Temporal, CE::Causal => ME::Causal, CE::Entity => ME::Entity, + _ => ME::Semantic, } }) .collect(); @@ -373,7 +373,6 @@ pub fn build_memory_router( } let fallback = manager.routing.fallback_route; match manager.routing.strategy { - StoreRoutingStrategy::Heuristic => Box::new(zeph_memory::HeuristicRouter), StoreRoutingStrategy::Llm => { let Some(provider) = manager.store_routing_provider.clone() else { tracing::warn!( @@ -398,6 +397,7 @@ pub fn build_memory_router( manager.routing.confidence_threshold, )) } + _ => Box::new(zeph_memory::HeuristicRouter), } } diff --git a/crates/zeph-agent-context/src/summarization/pruning.rs b/crates/zeph-agent-context/src/summarization/pruning.rs index b1c97ee0b..a264f915f 100644 --- a/crates/zeph-agent-context/src/summarization/pruning.rs +++ b/crates/zeph-agent-context/src/summarization/pruning.rs @@ -34,7 +34,7 @@ pub(crate) fn prune_tool_outputs( PruningStrategy::Mig => prune_tool_outputs_mig(summ, min_to_free), PruningStrategy::Subgoal => prune_tool_outputs_subgoal(summ, min_to_free), PruningStrategy::SubgoalMig => prune_tool_outputs_subgoal_mig(summ, min_to_free), - PruningStrategy::Reactive => prune_tool_outputs_oldest_first(summ, min_to_free), + _ => prune_tool_outputs_oldest_first(summ, min_to_free), } } diff --git a/crates/zeph-agent-context/src/summarization/scheduling.rs b/crates/zeph-agent-context/src/summarization/scheduling.rs index 43a62ccd7..839ee3454 100644 --- a/crates/zeph-agent-context/src/summarization/scheduling.rs +++ b/crates/zeph-agent-context/src/summarization/scheduling.rs @@ -80,10 +80,8 @@ pub(crate) fn maybe_soft_compact_mid_iteration(summ: &mut ContextSummarizationVi /// Only runs when a `TaskAware` or `Mig` pruning strategy is active. pub(crate) fn maybe_refresh_task_goal(summ: &mut ContextSummarizationView<'_>) { match &summ.context_manager.compression.pruning_strategy { - zeph_config::PruningStrategy::Reactive - | zeph_config::PruningStrategy::Subgoal - | zeph_config::PruningStrategy::SubgoalMig => return, zeph_config::PruningStrategy::TaskAware | zeph_config::PruningStrategy::Mig => {} + _ => return, } // Phase 1: apply completed background result. diff --git a/crates/zeph-channels/src/any.rs b/crates/zeph-channels/src/any.rs index a32bf69fe..f9dc96402 100644 --- a/crates/zeph-channels/src/any.rs +++ b/crates/zeph-channels/src/any.rs @@ -51,6 +51,7 @@ use crate::telegram::TelegramChannel; /// # }); /// ``` #[derive(Debug)] +#[non_exhaustive] pub enum AnyChannel { Cli(CliChannel), JsonCli(JsonCliChannel), diff --git a/crates/zeph-channels/src/line_editor.rs b/crates/zeph-channels/src/line_editor.rs index f27c6ec11..a35f964fc 100644 --- a/crates/zeph-channels/src/line_editor.rs +++ b/crates/zeph-channels/src/line_editor.rs @@ -29,6 +29,7 @@ use crossterm::{ /// /// Both [`read_line`] (TTY) and [`read_line_piped`] (non-TTY) return this type /// so the caller can handle all three cases uniformly. +#[non_exhaustive] pub enum ReadLineResult { /// A complete line was read. The trailing newline is stripped. Line(String), diff --git a/crates/zeph-channels/src/telegram_api_ext.rs b/crates/zeph-channels/src/telegram_api_ext.rs index 3a2dceb6f..077737e1d 100644 --- a/crates/zeph-channels/src/telegram_api_ext.rs +++ b/crates/zeph-channels/src/telegram_api_ext.rs @@ -92,6 +92,7 @@ pub struct GuestMessage { /// unrecognised status string is captured by the `Other` variant. #[derive(Debug, Clone, PartialEq, Eq, Deserialize)] #[serde(rename_all = "snake_case")] +#[non_exhaustive] pub enum ChatMemberStatus { /// The user is the chat creator. Creator, @@ -140,6 +141,7 @@ struct TelegramResponse { /// Errors returned by [`TelegramApiClient`] methods. #[derive(Debug, thiserror::Error)] +#[non_exhaustive] pub enum TelegramApiError { /// HTTP transport or status error. #[error("HTTP error: {0}")] diff --git a/crates/zeph-commands/src/lib.rs b/crates/zeph-commands/src/lib.rs index b47dc6366..3c3951132 100644 --- a/crates/zeph-commands/src/lib.rs +++ b/crates/zeph-commands/src/lib.rs @@ -109,6 +109,7 @@ pub enum CommandOutput { /// Category for grouping commands in `/help` output. #[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[non_exhaustive] pub enum SlashCategory { /// Session management: `/clear`, `/reset`, `/exit`, etc. Session, diff --git a/crates/zeph-common/src/audit.rs b/crates/zeph-common/src/audit.rs index b36473b80..55c25c421 100644 --- a/crates/zeph-common/src/audit.rs +++ b/crates/zeph-common/src/audit.rs @@ -11,6 +11,7 @@ /// /// Variants correspond to the four signal classes defined in spec 004-16, FR-007. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[non_exhaustive] pub enum AuditSignalType { /// A policy gate denied or flagged an operation. PolicyViolation, @@ -27,6 +28,7 @@ pub enum AuditSignalType { /// Mapped to a numeric multiplier by `TrajectorySeverityMultipliers`: /// `Low → 0.5`, `Medium → 1.0`, `High → 2.0` (defaults). #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[non_exhaustive] pub enum Severity { /// Minor or likely-benign signal. Low, diff --git a/crates/zeph-common/src/error_taxonomy.rs b/crates/zeph-common/src/error_taxonomy.rs index 767aaef67..ac8984a27 100644 --- a/crates/zeph-common/src/error_taxonomy.rs +++ b/crates/zeph-common/src/error_taxonomy.rs @@ -23,6 +23,7 @@ /// ``` #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)] #[serde(rename_all = "snake_case")] +#[non_exhaustive] pub enum ErrorDomain { /// The agent selected the wrong tool or misunderstood the task. /// Recovery: re-plan, pick a different tool or approach. @@ -76,6 +77,7 @@ impl ErrorDomain { /// Setup → `ParamHandling` → Execution → `ResultInterpretation`. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)] #[serde(rename_all = "snake_case")] +#[non_exhaustive] pub enum ToolInvocationPhase { /// Tool lookup/registration phase: was the tool name valid? Setup, diff --git a/crates/zeph-common/src/memory.rs b/crates/zeph-common/src/memory.rs index 319b64d55..8665940a2 100644 --- a/crates/zeph-common/src/memory.rs +++ b/crates/zeph-common/src/memory.rs @@ -20,6 +20,7 @@ use serde::{Deserialize, Serialize}; /// Serialises with `snake_case` names (`keyword`, `semantic`, `hybrid`, `graph`, `episodic`). #[derive(Debug, Clone, Copy, PartialEq, Eq, Default, serde::Serialize, serde::Deserialize)] #[serde(rename_all = "snake_case")] +#[non_exhaustive] pub enum MemoryRoute { /// Full-text search only (`SQLite` FTS5). Fast, good for keyword/exact queries. Keyword, @@ -79,6 +80,7 @@ pub trait AsyncMemoryRouter: MemoryRouter { /// assert_eq!(RecallView::default(), RecallView::Head); /// ``` #[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] +#[non_exhaustive] pub enum RecallView { /// Standard retrieval — no enrichment beyond what the base method provides. #[default] @@ -93,6 +95,7 @@ pub enum RecallView { /// The three abstraction levels in the compression spectrum. #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +#[non_exhaustive] pub enum CompressionLevel { /// Raw episodic messages — full fidelity, high token cost. Episodic, @@ -270,6 +273,7 @@ pub struct SpreadingActivationParams { /// MAGMA edge type: the semantic category of a relationship between two entities. #[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash, Serialize, Deserialize)] #[serde(rename_all = "snake_case")] +#[non_exhaustive] pub enum EdgeType { #[default] Semantic, diff --git a/crates/zeph-common/src/policy.rs b/crates/zeph-common/src/policy.rs index 1d57a2551..c6a42f2aa 100644 --- a/crates/zeph-common/src/policy.rs +++ b/crates/zeph-common/src/policy.rs @@ -23,6 +23,7 @@ pub struct PolicyMessage { /// Role for a [`PolicyMessage`]. #[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[non_exhaustive] pub enum PolicyRole { /// System-level instruction. System, diff --git a/crates/zeph-common/src/secret.rs b/crates/zeph-common/src/secret.rs index 151cd2142..40288ef68 100644 --- a/crates/zeph-common/src/secret.rs +++ b/crates/zeph-common/src/secret.rs @@ -85,6 +85,7 @@ impl fmt::Display for Secret { /// The `Backend(String)` variant is the escape hatch for third-party vault implementations: /// format the underlying error into the `String` when no more specific variant applies. #[derive(Debug, thiserror::Error)] +#[non_exhaustive] pub enum VaultError { #[error("secret not found: {0}")] NotFound(String), diff --git a/crates/zeph-common/src/task_supervisor.rs b/crates/zeph-common/src/task_supervisor.rs index d13b1358b..3f8e0f29d 100644 --- a/crates/zeph-common/src/task_supervisor.rs +++ b/crates/zeph-common/src/task_supervisor.rs @@ -62,6 +62,7 @@ use crate::BlockingSpawner; /// /// Used in [`TaskDescriptor`] to configure restart behaviour for a task. #[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[non_exhaustive] pub enum RestartPolicy { /// Task runs once; normal completion removes it from the registry. RunOnce, @@ -139,6 +140,7 @@ impl TaskHandle { /// Error returned by [`BlockingHandle::join`]. #[derive(Debug, PartialEq, Eq)] +#[non_exhaustive] pub enum BlockingError { /// The task panicked before producing a result. Panicked, @@ -233,6 +235,7 @@ impl BlockingHandle { /// Point-in-time state of a supervised task. #[derive(Debug, Clone, PartialEq, Eq)] +#[non_exhaustive] pub enum TaskStatus { /// Task is actively running. Running, diff --git a/crates/zeph-common/src/trust_level.rs b/crates/zeph-common/src/trust_level.rs index 694ec56a3..47af94114 100644 --- a/crates/zeph-common/src/trust_level.rs +++ b/crates/zeph-common/src/trust_level.rs @@ -29,6 +29,7 @@ use serde::{Deserialize, Serialize}; /// ``` #[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash, Deserialize, Serialize)] #[serde(rename_all = "lowercase")] +#[non_exhaustive] pub enum SkillTrustLevel { /// Built-in or user-audited skill: full tool access. Trusted, diff --git a/crates/zeph-config/src/agent.rs b/crates/zeph-config/src/agent.rs index 478dcc7a0..1355808b4 100644 --- a/crates/zeph-config/src/agent.rs +++ b/crates/zeph-config/src/agent.rs @@ -12,6 +12,7 @@ use crate::subagent::{HookDef, MemoryScope, PermissionMode}; /// /// Used in `SubAgentDef.model` frontmatter field. #[derive(Debug, Clone, PartialEq, Eq)] +#[non_exhaustive] pub enum ModelSpec { /// Use the parent agent's active provider at spawn time. Inherit, @@ -65,6 +66,7 @@ impl<'de> Deserialize<'de> for ModelSpec { /// ``` #[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Deserialize, Serialize)] #[serde(rename_all = "snake_case")] +#[non_exhaustive] pub enum ParentContextPolicy { /// Pass the parent history verbatim — legacy behaviour, no sanitization. Inherit, @@ -78,6 +80,7 @@ pub enum ParentContextPolicy { /// Controls how parent agent context is injected into a spawned sub-agent's task prompt. #[derive(Debug, Clone, Copy, Default, Serialize, Deserialize, PartialEq, Eq)] #[serde(rename_all = "snake_case")] +#[non_exhaustive] pub enum ContextInjectionMode { /// No parent context injected. None, diff --git a/crates/zeph-config/src/autonomous.rs b/crates/zeph-config/src/autonomous.rs index d7e79e689..c8fafa70e 100644 --- a/crates/zeph-config/src/autonomous.rs +++ b/crates/zeph-config/src/autonomous.rs @@ -16,6 +16,7 @@ use serde::{Deserialize, Serialize}; /// - `Running` / `Verifying` → `Failed` (unrecoverable error) #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "snake_case")] +#[non_exhaustive] pub enum AutonomousState { /// The agent is actively running multi-turn execution. Running, diff --git a/crates/zeph-config/src/channels.rs b/crates/zeph-config/src/channels.rs index e24bb5939..9f834471c 100644 --- a/crates/zeph-config/src/channels.rs +++ b/crates/zeph-config/src/channels.rs @@ -17,6 +17,7 @@ pub use crate::mcp_security::ToolSecurityMeta; /// Controls SSRF validation, tool filtering, and data-flow policy enforcement. #[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "lowercase")] +#[non_exhaustive] pub enum McpTrustLevel { /// Full trust — all tools exposed, SSRF check skipped. Use for operator-controlled servers. Trusted, @@ -643,6 +644,7 @@ impl Default for ToolPruningConfig { /// circular crate dependency (`zeph-config` → `zeph-mcp`). #[derive(Debug, Clone, Copy, Default, Deserialize, Serialize, PartialEq, Eq)] #[serde(rename_all = "lowercase")] +#[non_exhaustive] pub enum ToolDiscoveryStrategyConfig { /// Embedding-based cosine similarity retrieval. Fast, no LLM call per turn. Embedding, @@ -999,6 +1001,7 @@ impl Default for McpOAuthConfig { /// Where OAuth tokens are stored. #[derive(Debug, Clone, Default, Deserialize, Serialize)] #[serde(rename_all = "lowercase")] +#[non_exhaustive] pub enum OAuthTokenStorage { /// Persisted in the age vault (default). #[default] diff --git a/crates/zeph-config/src/classifiers.rs b/crates/zeph-config/src/classifiers.rs index 77c1737e0..51ad31914 100644 --- a/crates/zeph-config/src/classifiers.rs +++ b/crates/zeph-config/src/classifiers.rs @@ -79,6 +79,7 @@ where /// Only safe for well-calibrated models or when FPR is verified on your workload. #[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize)] #[serde(rename_all = "snake_case")] +#[non_exhaustive] pub enum InjectionEnforcementMode { /// Log + metric only, never block. Warn, diff --git a/crates/zeph-config/src/dump_format.rs b/crates/zeph-config/src/dump_format.rs index 89c773931..826e73728 100644 --- a/crates/zeph-config/src/dump_format.rs +++ b/crates/zeph-config/src/dump_format.rs @@ -6,6 +6,7 @@ use serde::{Deserialize, Serialize}; /// Output format for debug dump files. #[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "lowercase")] +#[non_exhaustive] pub enum DumpFormat { /// Write LLM requests as pretty-printed internal zeph-llm JSON (`{id}-request.json`). #[default] diff --git a/crates/zeph-config/src/error.rs b/crates/zeph-config/src/error.rs index 16a622b4a..07226ef4e 100644 --- a/crates/zeph-config/src/error.rs +++ b/crates/zeph-config/src/error.rs @@ -7,6 +7,7 @@ use zeph_common::secret::VaultError; /// /// Covers file I/O, TOML parsing, validation, and vault resolution. #[derive(Debug, thiserror::Error)] +#[non_exhaustive] pub enum ConfigError { #[error("failed to read config file: {0}")] Io(#[from] std::io::Error), diff --git a/crates/zeph-config/src/experiment.rs b/crates/zeph-config/src/experiment.rs index 4a27c6545..e269869eb 100644 --- a/crates/zeph-config/src/experiment.rs +++ b/crates/zeph-config/src/experiment.rs @@ -26,6 +26,7 @@ use serde::{Deserialize, Serialize}; /// ``` #[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize, JsonSchema)] #[serde(rename_all = "snake_case")] +#[non_exhaustive] pub enum FailureStrategy { /// Abort the entire graph and cancel all running tasks. #[default] diff --git a/crates/zeph-config/src/features.rs b/crates/zeph-config/src/features.rs index 62721a66d..248e3823a 100644 --- a/crates/zeph-config/src/features.rs +++ b/crates/zeph-config/src/features.rs @@ -243,6 +243,7 @@ fn default_gateway_webhook_send_timeout_secs() -> u64 { /// Controls how skills are formatted in the system prompt. #[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Deserialize, Serialize)] #[serde(rename_all = "lowercase")] +#[non_exhaustive] pub enum SkillPromptMode { Full, Compact, @@ -1028,6 +1029,7 @@ impl Default for SchedulerConfig { /// Known variants map to built-in handlers; `Custom` accommodates user-defined task types. #[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)] #[serde(rename_all = "snake_case")] +#[non_exhaustive] pub enum ScheduledTaskKind { MemoryCleanup, SkillRefresh, diff --git a/crates/zeph-config/src/learning.rs b/crates/zeph-config/src/learning.rs index c8ba6d752..626c4b7d3 100644 --- a/crates/zeph-config/src/learning.rs +++ b/crates/zeph-config/src/learning.rs @@ -155,6 +155,7 @@ fn default_heuristic_promotion_interval_hours() -> u64 { /// Strategy for detecting implicit user corrections. #[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Deserialize, Serialize)] #[serde(rename_all = "lowercase")] +#[non_exhaustive] pub enum DetectorMode { /// Pattern-matching only — zero LLM calls. Default behavior. #[default] diff --git a/crates/zeph-config/src/logging.rs b/crates/zeph-config/src/logging.rs index 24901688b..28b115681 100644 --- a/crates/zeph-config/src/logging.rs +++ b/crates/zeph-config/src/logging.rs @@ -16,6 +16,7 @@ fn default_log_max_files() -> usize { /// Log file rotation strategy. #[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Deserialize, Serialize)] #[serde(rename_all = "lowercase")] +#[non_exhaustive] pub enum LogRotation { #[default] Daily, diff --git a/crates/zeph-config/src/mcp_security.rs b/crates/zeph-config/src/mcp_security.rs index 1538aaf5e..cbe76c3c3 100644 --- a/crates/zeph-config/src/mcp_security.rs +++ b/crates/zeph-config/src/mcp_security.rs @@ -16,6 +16,7 @@ use serde::{Deserialize, Serialize}; /// `max()` comparisons when computing the worst-case sensitivity of a tool set. #[derive(Debug, Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)] #[serde(rename_all = "lowercase")] +#[non_exhaustive] pub enum DataSensitivity { /// No sensitive data. #[default] @@ -34,6 +35,7 @@ pub enum DataSensitivity { /// Stored inside [`ToolSecurityMeta::capabilities`] and used by the data-flow policy. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)] #[serde(rename_all = "snake_case")] +#[non_exhaustive] pub enum CapabilityClass { /// Reads from the local filesystem. FilesystemRead, diff --git a/crates/zeph-config/src/memory.rs b/crates/zeph-config/src/memory.rs index 543c2f7bc..279862777 100644 --- a/crates/zeph-config/src/memory.rs +++ b/crates/zeph-config/src/memory.rs @@ -658,6 +658,7 @@ impl Default for NoteLinkingConfig { /// Vector backend selector for embedding storage. #[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Deserialize, Serialize)] #[serde(rename_all = "lowercase")] +#[non_exhaustive] pub enum VectorBackend { Qdrant, #[default] @@ -1542,6 +1543,7 @@ impl Default for DigestConfig { /// Context assembly strategy (#2288). #[derive(Debug, Clone, Copy, Default, Deserialize, Serialize, PartialEq, Eq)] #[serde(rename_all = "snake_case")] +#[non_exhaustive] pub enum ContextStrategy { /// Full conversation history trimmed to budget, with memory augmentation. /// This is the default and existing behavior. @@ -1686,6 +1688,7 @@ impl Default for SemanticConfig { /// Consider raising `memory.recall_tokens` proportionally when switching to `Structured`. #[derive(Debug, Clone, Copy, Default, Deserialize, Serialize, PartialEq, Eq, Hash)] #[serde(rename_all = "snake_case")] +#[non_exhaustive] pub enum ContextFormat { /// Emit a labeled header per snippet: /// `[Memory | | | relevance: ]` followed by the content. @@ -1882,6 +1885,7 @@ impl Default for HebbianConfig { /// Compression strategy for active context compression (#1161). #[derive(Debug, Clone, Default, Deserialize, Serialize, PartialEq)] #[serde(tag = "strategy", rename_all = "snake_case")] +#[non_exhaustive] pub enum CompressionStrategy { /// Compress only when reactive compaction fires (current behavior). #[default] @@ -1909,6 +1913,7 @@ pub enum CompressionStrategy { /// heuristic with scored eviction. #[derive(Debug, Clone, Copy, Default, Serialize, PartialEq, Eq)] #[serde(rename_all = "snake_case")] +#[non_exhaustive] pub enum PruningStrategy { /// Oldest-first eviction — current default behavior. #[default] @@ -2125,6 +2130,7 @@ impl Default for TypedPagesConfig { /// Enforcement mode for typed-page compaction (#3630). #[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Deserialize, Serialize, JsonSchema)] #[serde(rename_all = "snake_case")] +#[non_exhaustive] pub enum TypedPagesEnforcement { /// Classify and audit only. Zero behavioral change relative to the untyped path. #[default] @@ -2188,6 +2194,7 @@ impl Default for SidequestConfig { /// The default (`synapse`) preserves existing SYNAPSE spreading-activation behavior. #[derive(Debug, Clone, Copy, PartialEq, Eq, Default, serde::Serialize, serde::Deserialize)] #[serde(rename_all = "snake_case")] +#[non_exhaustive] pub enum GraphRetrievalStrategy { /// SYNAPSE spreading activation (default, existing behavior). #[default] @@ -2461,6 +2468,7 @@ pub struct GraphConfig { schemars::JsonSchema, )] #[serde(rename_all = "snake_case")] +#[non_exhaustive] pub enum SimilarityMethod { /// Normalized Levenshtein edit distance. #[default] @@ -2484,6 +2492,7 @@ pub enum SimilarityMethod { schemars::JsonSchema, )] #[serde(rename_all = "snake_case")] +#[non_exhaustive] pub enum ConflictResolutionStrategy { /// Mark the pair as a candidate but do not supersede either edge. #[default] @@ -2927,6 +2936,7 @@ fn default_rl_retrain_interval_secs() -> u64 { /// `Rl` replaces the LLM-based `future_utility` factor with a trained logistic regression model. #[derive(Debug, Clone, Default, PartialEq, Eq, serde::Deserialize, serde::Serialize)] #[serde(rename_all = "snake_case")] +#[non_exhaustive] pub enum AdmissionStrategy { /// Current A-MAC behavior: weighted heuristics + optional LLM call. Default. #[default] @@ -3099,6 +3109,7 @@ impl Default for AdmissionConfig { /// Routing strategy for `[memory.store_routing]`. #[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Deserialize, Serialize)] #[serde(rename_all = "snake_case")] +#[non_exhaustive] pub enum StoreRoutingStrategy { /// Pure heuristic pattern matching. Zero LLM calls. Default. #[default] @@ -3743,6 +3754,7 @@ impl Default for ReasoningConfig { /// Serialises as `"ebbinghaus"` in TOML/JSON so existing configs remain valid. #[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Deserialize, Serialize)] #[serde(rename_all = "lowercase")] +#[non_exhaustive] pub enum EvictionPolicy { /// Ebbinghaus forgetting-curve eviction. #[default] @@ -3827,6 +3839,7 @@ impl Default for CompressionGuidelinesConfig { /// `zeph-memory` re-exports this type from here. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, JsonSchema)] #[serde(rename_all = "lowercase")] +#[non_exhaustive] pub enum ProbeCategory { /// Did specific facts survive? (file paths, function names, values, decisions) Recall, @@ -3953,6 +3966,7 @@ pub struct MemCotConfig { /// Maps 1-to-1 to `zeph_memory::RecallView`. #[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)] #[serde(rename_all = "snake_case")] +#[non_exhaustive] pub enum RecallViewConfig { /// Standard retrieval — no enrichment. Byte-identical to legacy behaviour. #[default] diff --git a/crates/zeph-config/src/migrate/mod.rs b/crates/zeph-config/src/migrate/mod.rs index 6928f8b32..23c247c54 100644 --- a/crates/zeph-config/src/migrate/mod.rs +++ b/crates/zeph-config/src/migrate/mod.rs @@ -46,6 +46,7 @@ static CANONICAL_ORDER: &[&str] = &[ /// Error type for migration failures. #[derive(Debug, thiserror::Error)] +#[non_exhaustive] pub enum MigrateError { /// Failed to parse the user's config. #[error("failed to parse input config: {0}")] diff --git a/crates/zeph-config/src/quality.rs b/crates/zeph-config/src/quality.rs index 0e21b2e8c..121ecf430 100644 --- a/crates/zeph-config/src/quality.rs +++ b/crates/zeph-config/src/quality.rs @@ -19,6 +19,7 @@ use crate::providers::ProviderName; /// When to trigger the self-check pipeline. #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)] #[serde(rename_all = "snake_case")] +#[non_exhaustive] pub enum TriggerPolicy { /// Run only when the turn has retrieved context. #[default] diff --git a/crates/zeph-config/src/sanitizer.rs b/crates/zeph-config/src/sanitizer.rs index 8967ba3fb..dc8454a58 100644 --- a/crates/zeph-config/src/sanitizer.rs +++ b/crates/zeph-config/src/sanitizer.rs @@ -464,6 +464,7 @@ impl Default for PiiFilterConfig { /// What happens when the guardrail flags input. #[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Deserialize, Serialize)] #[serde(rename_all = "lowercase")] +#[non_exhaustive] pub enum GuardrailAction { /// Block the input and return an error message to the user. #[default] @@ -475,6 +476,7 @@ pub enum GuardrailAction { /// Behavior on timeout or LLM error. #[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Deserialize, Serialize)] #[serde(rename_all = "lowercase")] +#[non_exhaustive] pub enum GuardrailFailStrategy { /// Block input on timeout/error (safe default for security-sensitive deployments). #[default] diff --git a/crates/zeph-config/src/security.rs b/crates/zeph-config/src/security.rs index cfd250c2c..70ee2cde9 100644 --- a/crates/zeph-config/src/security.rs +++ b/crates/zeph-config/src/security.rs @@ -402,6 +402,7 @@ impl Default for ShadowSentinelConfig { /// Controls whether a zero-match glob is a fatal error or a warning. #[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize, Default)] #[serde(rename_all = "snake_case")] +#[non_exhaustive] pub enum PatternStrictness { /// All namespaces are strict — zero-match globs are fatal. Strict, diff --git a/crates/zeph-config/src/subagent.rs b/crates/zeph-config/src/subagent.rs index f4b9b844d..5c17cd936 100644 --- a/crates/zeph-config/src/subagent.rs +++ b/crates/zeph-config/src/subagent.rs @@ -13,6 +13,7 @@ use serde::{Deserialize, Serialize}; /// execution and returns only the plan text. #[derive(Debug, Clone, Copy, Default, Serialize, Deserialize, PartialEq, Eq)] #[serde(rename_all = "snake_case")] +#[non_exhaustive] pub enum PermissionMode { /// Standard behavior — prompt for each action (sub-agents auto-approve). #[default] @@ -34,6 +35,7 @@ pub enum PermissionMode { /// Determines where the agent's `MEMORY.md` and topic files are stored across sessions. #[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)] #[serde(rename_all = "snake_case")] +#[non_exhaustive] pub enum MemoryScope { /// User-level: `~/.zeph/agent-memory//`. User, @@ -50,6 +52,7 @@ pub enum MemoryScope { /// Controls which tools the sub-agent may call, independent of the global tool denylist. #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(rename_all = "snake_case")] +#[non_exhaustive] pub enum ToolPolicy { /// Only the listed tool IDs are accessible. AllowList(Vec), @@ -115,6 +118,7 @@ impl SkillFilter { /// ``` #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(tag = "type", rename_all = "snake_case")] +#[non_exhaustive] pub enum HookAction { /// Execute a shell command via `sh -c`. Command { diff --git a/crates/zeph-config/src/telemetry.rs b/crates/zeph-config/src/telemetry.rs index 3a2a35af9..54b36f80b 100644 --- a/crates/zeph-config/src/telemetry.rs +++ b/crates/zeph-config/src/telemetry.rs @@ -35,6 +35,7 @@ fn default_system_metrics_interval_secs() -> u64 { /// feature). #[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Deserialize, Serialize)] #[serde(rename_all = "lowercase")] +#[non_exhaustive] pub enum TelemetryBackend { /// Write `{trace_dir}/{session_id}_{timestamp}.json` Chrome traces. #[default] diff --git a/crates/zeph-config/src/tools.rs b/crates/zeph-config/src/tools.rs index 082b9a6aa..750ef59cf 100644 --- a/crates/zeph-config/src/tools.rs +++ b/crates/zeph-config/src/tools.rs @@ -20,6 +20,7 @@ use zeph_common::SkillTrustLevel; /// Tool access level controlling agent autonomy. #[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Deserialize, Serialize)] #[serde(rename_all = "lowercase")] +#[non_exhaustive] pub enum AutonomyLevel { /// Read-only tools: `read`, `find_path`, `grep`, `list_directory`, `web_scrape`, `fetch` ReadOnly, @@ -33,6 +34,7 @@ pub enum AutonomyLevel { /// Action a permission rule resolves to. #[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize)] #[serde(rename_all = "lowercase")] +#[non_exhaustive] pub enum PermissionAction { /// Allow the tool call unconditionally. Allow, @@ -214,6 +216,7 @@ impl Default for PreExecutionVerifierConfig { /// Effect applied when a policy rule matches. #[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize)] #[serde(rename_all = "snake_case")] +#[non_exhaustive] pub enum PolicyEffect { /// Allow the tool call. Allow, @@ -224,6 +227,7 @@ pub enum PolicyEffect { /// Default effect when no policy rule matches. #[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Deserialize, Serialize)] #[serde(rename_all = "lowercase")] +#[non_exhaustive] pub enum DefaultEffect { /// Allow the call when no rule matches. Allow, @@ -279,6 +283,7 @@ pub struct PolicyRuleConfig { /// Baseline restriction profile for the OS-level sandbox. #[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Deserialize, Serialize)] #[serde(rename_all = "kebab-case")] +#[non_exhaustive] pub enum SandboxProfile { /// Read-only to `allow_read` paths, no writes, no network. ReadOnly, @@ -302,6 +307,7 @@ fn default_sandbox_profile() -> SandboxProfile { /// (`"auto"`, `"seatbelt"`, `"landlock-bwrap"`, `"noop"`). #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)] #[serde(rename_all = "kebab-case")] +#[non_exhaustive] pub enum SandboxBackend { /// Automatically select the best available backend for the current OS. #[default] @@ -820,6 +826,7 @@ pub struct AuthorizationConfig { /// /// Deserializes from a string in TOML: `"stdout"`, `"stderr"`, or a file path. #[derive(Debug, Clone, PartialEq, Eq, Default)] +#[non_exhaustive] pub enum AuditDestination { /// Write audit entries to standard output. #[default] @@ -1058,6 +1065,7 @@ impl Default for ScrapeConfig { /// Speculative tool execution mode. #[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Deserialize, Serialize)] #[serde(rename_all = "kebab-case")] +#[non_exhaustive] pub enum SpeculationMode { /// No speculation; uses existing synchronous path. #[default] diff --git a/crates/zeph-config/src/ui.rs b/crates/zeph-config/src/ui.rs index 31dcbc80d..113ee97ff 100644 --- a/crates/zeph-config/src/ui.rs +++ b/crates/zeph-config/src/ui.rs @@ -108,6 +108,7 @@ fn default_lsp_call_timeout_secs() -> u64 { /// ``` #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)] #[serde(rename_all = "lowercase")] +#[non_exhaustive] pub enum AcpAuthMethod { /// Vault-backed agent auth — the sole supported method in PR 4. Agent, @@ -137,6 +138,7 @@ fn default_acp_auth_methods() -> Vec { /// Error returned when parsing an [`AdditionalDir`] fails. #[derive(Debug, thiserror::Error)] +#[non_exhaustive] pub enum AdditionalDirError { /// The raw path contains a `..` component. #[error("path `{0}` contains `..` traversal")] @@ -273,6 +275,7 @@ impl<'de> serde::Deserialize<'de> for AdditionalDir { /// ``` #[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Deserialize, Serialize)] #[serde(rename_all = "lowercase")] +#[non_exhaustive] pub enum ToolDensity { /// Single-line summary only (tool name + line count, no output body). Compact, @@ -355,6 +358,7 @@ impl Default for FleetConfig { /// ACP server transport mode. #[derive(Debug, Clone, Default, Deserialize, Serialize)] #[serde(rename_all = "lowercase")] +#[non_exhaustive] pub enum AcpTransport { /// JSON-RPC over stdin/stdout (default, IDE embedding). #[default] @@ -642,6 +646,7 @@ impl Default for AcpLspConfig { /// Minimum diagnostic severity to include in LSP context injection. #[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Deserialize, Serialize)] #[serde(rename_all = "lowercase")] +#[non_exhaustive] pub enum DiagnosticSeverity { #[default] Error, diff --git a/crates/zeph-context/src/assembler.rs b/crates/zeph-context/src/assembler.rs index 53f6c6468..1fc51180f 100644 --- a/crates/zeph-context/src/assembler.rs +++ b/crates/zeph-context/src/assembler.rs @@ -124,7 +124,6 @@ fn resolve_effective_strategy( sidequest_turn_counter: u64, ) -> zeph_config::ContextStrategy { match memory.context_strategy { - zeph_config::ContextStrategy::FullHistory => zeph_config::ContextStrategy::FullHistory, zeph_config::ContextStrategy::MemoryFirst => zeph_config::ContextStrategy::MemoryFirst, zeph_config::ContextStrategy::Adaptive => { if sidequest_turn_counter >= u64::from(memory.crossover_turn_threshold) { @@ -133,6 +132,7 @@ fn resolve_effective_strategy( zeph_config::ContextStrategy::FullHistory } } + _ => zeph_config::ContextStrategy::FullHistory, } } @@ -427,9 +427,9 @@ pub(crate) async fn fetch_graph_facts( let edge_types = classify_graph_subgraph(effective_query); let view = match memory.memcot_config.recall_view { - zeph_config::RecallViewConfig::Head => RecallView::Head, zeph_config::RecallViewConfig::ZoomIn => RecallView::ZoomIn, zeph_config::RecallViewConfig::ZoomOut => RecallView::ZoomOut, + _ => RecallView::Head, }; let sa_params = if sa_config.enabled { diff --git a/crates/zeph-core/src/agent/context/summarization/adapters.rs b/crates/zeph-core/src/agent/context/summarization/adapters.rs index c634c457e..633c4c13e 100644 --- a/crates/zeph-core/src/agent/context/summarization/adapters.rs +++ b/crates/zeph-core/src/agent/context/summarization/adapters.rs @@ -223,6 +223,7 @@ impl CompactionProbeCallback for AgentProbe { self.metrics.record_compaction_probe_error(); ProbeOutcome::Pass } + _ => ProbeOutcome::Pass, } } } diff --git a/crates/zeph-core/src/agent/context/summarization/pruning.rs b/crates/zeph-core/src/agent/context/summarization/pruning.rs index 0662c9dbf..a615273ae 100644 --- a/crates/zeph-core/src/agent/context/summarization/pruning.rs +++ b/crates/zeph-core/src/agent/context/summarization/pruning.rs @@ -126,7 +126,7 @@ impl Agent { PruningStrategy::SubgoalMig => { return self.prune_tool_outputs_subgoal_mig(min_to_free); } - PruningStrategy::Reactive => {} // fall through to oldest-first + _ => {} // fall through to oldest-first } } self.prune_tool_outputs_oldest_first(min_to_free) diff --git a/crates/zeph-core/src/agent/log_commands.rs b/crates/zeph-core/src/agent/log_commands.rs index 291f01e83..4674fff73 100644 --- a/crates/zeph-core/src/agent/log_commands.rs +++ b/crates/zeph-core/src/agent/log_commands.rs @@ -20,7 +20,7 @@ pub(crate) fn format_logging_status(logging: &LoggingConfig, out: &mut String) { let rotation_str = match logging.rotation { LogRotation::Daily => "daily", LogRotation::Hourly => "hourly", - LogRotation::Never => "never", + _ => "never", }; let _ = writeln!(out, "Rotation: {rotation_str}"); let _ = writeln!(out, "Max files: {}", logging.max_files); diff --git a/crates/zeph-core/src/agent/mod.rs b/crates/zeph-core/src/agent/mod.rs index 29718ebd9..18322db41 100644 --- a/crates/zeph-core/src/agent/mod.rs +++ b/crates/zeph-core/src/agent/mod.rs @@ -817,11 +817,11 @@ impl Agent { permission_mode: def.map_or_else(String::new, |d| { use zeph_subagent::def::PermissionMode; match d.permissions.permission_mode { - PermissionMode::Default => String::new(), PermissionMode::AcceptEdits => "accept_edits".into(), PermissionMode::DontAsk => "dont_ask".into(), PermissionMode::BypassPermissions => "bypass_permissions".into(), PermissionMode::Plan => "plan".into(), + _ => String::new(), } }), transcript_dir: mgr @@ -2433,6 +2433,7 @@ impl Agent { Some(zeph_subagent::MemoryScope::User) => " [memory:user]", Some(zeph_subagent::MemoryScope::Project) => " [memory:project]", Some(zeph_subagent::MemoryScope::Local) => " [memory:local]", + Some(_) => " [memory:unknown]", None => "", }; if let Some(ref src) = d.source { @@ -2555,6 +2556,7 @@ impl Agent { Some(zeph_subagent::MemoryScope::User) => " [memory:user]", Some(zeph_subagent::MemoryScope::Project) => " [memory:project]", Some(zeph_subagent::MemoryScope::Local) => " [memory:local]", + Some(_) => " [memory:unknown]", None => "", }; if let Some(ref src) = d.source { @@ -2933,10 +2935,10 @@ impl Agent { }; let initial_level = match source_kind { zeph_memory::store::SourceKind::Bundled => &trust_cfg.bundled_level, - zeph_memory::store::SourceKind::Hub => &trust_cfg.default_level, zeph_memory::store::SourceKind::Local | zeph_memory::store::SourceKind::File => { &trust_cfg.local_level } + _ => &trust_cfg.default_level, }; let existing = memory .sqlite() diff --git a/crates/zeph-core/src/agent/policy_commands.rs b/crates/zeph-core/src/agent/policy_commands.rs index 2ccff0e0c..4ce622f9c 100644 --- a/crates/zeph-core/src/agent/policy_commands.rs +++ b/crates/zeph-core/src/agent/policy_commands.rs @@ -30,7 +30,7 @@ impl Agent { .map_or(policy_config.rules.len(), |e| e.rule_count()); let default_str = match policy_config.default_effect { DefaultEffect::Allow => "allow", - DefaultEffect::Deny => "deny", + _ => "deny", }; let status_str = if policy_config.enabled { "enabled" diff --git a/crates/zeph-core/src/agent/speculative/cache.rs b/crates/zeph-core/src/agent/speculative/cache.rs index 345277d43..c00fe66cd 100644 --- a/crates/zeph-core/src/agent/speculative/cache.rs +++ b/crates/zeph-core/src/agent/speculative/cache.rs @@ -73,6 +73,9 @@ impl SpeculativeHandle { Err(BlockingError::SupervisorDropped) => Err(ToolError::Execution( std::io::Error::other("speculative task cancelled"), )), + Err(_) => Err(ToolError::Execution(std::io::Error::other( + "speculative task failed", + ))), } } } diff --git a/crates/zeph-core/src/debug_dump/mod.rs b/crates/zeph-core/src/debug_dump/mod.rs index 0a7e8ab27..e20475857 100644 --- a/crates/zeph-core/src/debug_dump/mod.rs +++ b/crates/zeph-core/src/debug_dump/mod.rs @@ -98,9 +98,9 @@ impl DebugDumper { return id; } let json = match self.format { - DumpFormat::Json => json_dump(request), DumpFormat::Raw => raw_dump(request), DumpFormat::Trace => unreachable!("handled above"), + _ => json_dump(request), }; self.write(&format!("{id:04}-request.json"), json.as_bytes()); id diff --git a/crates/zeph-core/src/lsp_hooks/diagnostics.rs b/crates/zeph-core/src/lsp_hooks/diagnostics.rs index d11ab081f..1a9176f2d 100644 --- a/crates/zeph-core/src/lsp_hooks/diagnostics.rs +++ b/crates/zeph-core/src/lsp_hooks/diagnostics.rs @@ -22,7 +22,7 @@ fn severity_threshold(min: DiagnosticSeverity) -> u64 { DiagnosticSeverity::Error => 1, DiagnosticSeverity::Warning => 2, DiagnosticSeverity::Info => 3, - DiagnosticSeverity::Hint => 4, + _ => 4, } } diff --git a/crates/zeph-core/src/quality/config.rs b/crates/zeph-core/src/quality/config.rs index 7f291636d..7fee09913 100644 --- a/crates/zeph-core/src/quality/config.rs +++ b/crates/zeph-core/src/quality/config.rs @@ -168,9 +168,9 @@ impl From<&zeph_config::QualityConfig> for QualityConfig { proposer_provider: c.proposer_provider.clone(), checker_provider: c.checker_provider.clone(), trigger: match c.trigger { - zeph_config::TriggerPolicy::HasRetrieval => TriggerPolicy::HasRetrieval, zeph_config::TriggerPolicy::Always => TriggerPolicy::Always, zeph_config::TriggerPolicy::Manual => TriggerPolicy::Manual, + _ => TriggerPolicy::HasRetrieval, }, min_evidence: c.min_evidence, async_run: c.async_run, diff --git a/crates/zeph-gateway/src/error.rs b/crates/zeph-gateway/src/error.rs index 3e2b745b6..afebda39f 100644 --- a/crates/zeph-gateway/src/error.rs +++ b/crates/zeph-gateway/src/error.rs @@ -7,6 +7,7 @@ use thiserror::Error; /// /// All variants implement [`std::error::Error`] via [`thiserror`]. #[derive(Debug, Error)] +#[non_exhaustive] pub enum GatewayError { /// The server could not bind to the requested address. /// diff --git a/crates/zeph-mcp/src/manager.rs b/crates/zeph-mcp/src/manager.rs index 7d66d8555..1b100edce 100644 --- a/crates/zeph-mcp/src/manager.rs +++ b/crates/zeph-mcp/src/manager.rs @@ -1799,6 +1799,7 @@ fn apply_attestation( .filter(|t| expected_tools.iter().any(|e| e == &t.name)) .collect() } + _ => tools, } } } @@ -1813,7 +1814,6 @@ fn apply_allowlist( status_tx: Option<&StatusTx>, ) -> Vec { match trust_level { - McpTrustLevel::Trusted => tools, McpTrustLevel::Untrusted => match allowlist { None => { let msg = format!( @@ -1871,6 +1871,7 @@ fn apply_allowlist( filtered } } + _ => tools, } } diff --git a/crates/zeph-memory/src/compaction_probe.rs b/crates/zeph-memory/src/compaction_probe.rs index 2b9cf8cf4..b1d9d177a 100644 --- a/crates/zeph-memory/src/compaction_probe.rs +++ b/crates/zeph-memory/src/compaction_probe.rs @@ -60,6 +60,7 @@ impl Default for ProbeQuestion { /// Three-tier verdict for compaction probe quality. #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] +#[non_exhaustive] pub enum ProbeVerdict { /// Score >= `threshold`: summary preserves enough context. Proceed. Pass, diff --git a/crates/zeph-memory/src/consolidation.rs b/crates/zeph-memory/src/consolidation.rs index 16c6d1467..12b2047c5 100644 --- a/crates/zeph-memory/src/consolidation.rs +++ b/crates/zeph-memory/src/consolidation.rs @@ -39,6 +39,7 @@ use zeph_common::math::cosine_similarity; /// not based on similarity clustering. #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[serde(tag = "op", rename_all = "snake_case")] +#[non_exhaustive] pub enum TopologyOp { /// Merge N similar messages into one consolidated entry. Merge { diff --git a/crates/zeph-memory/src/document/error.rs b/crates/zeph-memory/src/document/error.rs index ffeed198e..f62481b44 100644 --- a/crates/zeph-memory/src/document/error.rs +++ b/crates/zeph-memory/src/document/error.rs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 #[derive(Debug, thiserror::Error)] +#[non_exhaustive] pub enum DocumentError { #[error("IO error: {0}")] Io(#[from] std::io::Error), diff --git a/crates/zeph-memory/src/embedding_registry.rs b/crates/zeph-memory/src/embedding_registry.rs index c029f32fd..072cb9208 100644 --- a/crates/zeph-memory/src/embedding_registry.rs +++ b/crates/zeph-memory/src/embedding_registry.rs @@ -59,6 +59,7 @@ pub struct SyncStats { /// Errors produced by [`EmbeddingRegistry`]. #[derive(Debug, thiserror::Error)] +#[non_exhaustive] pub enum EmbeddingRegistryError { #[error("vector store error: {0}")] VectorStore(#[from] VectorStoreError), diff --git a/crates/zeph-memory/src/embedding_store.rs b/crates/zeph-memory/src/embedding_store.rs index 94d49363a..540abffac 100644 --- a/crates/zeph-memory/src/embedding_store.rs +++ b/crates/zeph-memory/src/embedding_store.rs @@ -26,6 +26,7 @@ use crate::vector_store::{FieldCondition, FieldValue, VectorFilter, VectorPoint, /// The kind is encoded in the Qdrant payload so search filters can restrict /// results to one category. #[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[non_exhaustive] pub enum MessageKind { /// A normal conversation message. Regular, diff --git a/crates/zeph-memory/src/error.rs b/crates/zeph-memory/src/error.rs index f96092d81..8f14cc8d4 100644 --- a/crates/zeph-memory/src/error.rs +++ b/crates/zeph-memory/src/error.rs @@ -16,6 +16,7 @@ /// } /// ``` #[derive(Debug, thiserror::Error)] +#[non_exhaustive] pub enum MemoryError { #[error("database error: {0}")] Sqlx(#[from] zeph_db::SqlxError), diff --git a/crates/zeph-memory/src/facade.rs b/crates/zeph-memory/src/facade.rs index 604eeb9a2..4df86775d 100644 --- a/crates/zeph-memory/src/facade.rs +++ b/crates/zeph-memory/src/facade.rs @@ -90,6 +90,7 @@ pub struct MemoryMatch { /// Which memory backend produced a [`MemoryMatch`]. #[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[non_exhaustive] pub enum MemorySource { /// Qdrant vector search. Semantic, diff --git a/crates/zeph-memory/src/graph/conflict.rs b/crates/zeph-memory/src/graph/conflict.rs index 1492f51a4..357caf840 100644 --- a/crates/zeph-memory/src/graph/conflict.rs +++ b/crates/zeph-memory/src/graph/conflict.rs @@ -41,6 +41,7 @@ use crate::graph::types::Edge; /// a circular crate dependency (`zeph-memory` → `zeph-config` → `zeph-mcp` → `zeph-memory`). /// `zeph-config` re-exports its own copy; callers convert between the two. #[derive(Debug, Clone, PartialEq, Eq)] +#[non_exhaustive] pub enum ConflictStrategy { /// Pick the edge with the most recent `valid_from` timestamp. Recency, diff --git a/crates/zeph-memory/src/graph/ontology.rs b/crates/zeph-memory/src/graph/ontology.rs index fda756f7e..fa0ba160c 100644 --- a/crates/zeph-memory/src/graph/ontology.rs +++ b/crates/zeph-memory/src/graph/ontology.rs @@ -38,6 +38,7 @@ use crate::error::MemoryError; /// TOML format declares it per predicate without an `edge_type` field (critic nit #2). Per-edge-type /// overrides are a future extension. #[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] +#[non_exhaustive] pub enum Cardinality { /// Single-valued: conflict resolver picks one head edge when multiples coexist. One, diff --git a/crates/zeph-memory/src/graph/resolver/mod.rs b/crates/zeph-memory/src/graph/resolver/mod.rs index 18eace8be..ef78e04c5 100644 --- a/crates/zeph-memory/src/graph/resolver/mod.rs +++ b/crates/zeph-memory/src/graph/resolver/mod.rs @@ -38,6 +38,7 @@ const EMBED_TIMEOUT_SECS: u64 = 30; /// Outcome of an entity resolution attempt. #[derive(Debug, Clone, PartialEq)] +#[non_exhaustive] pub enum ResolutionOutcome { /// Exact name+type match in `SQLite`. ExactMatch, diff --git a/crates/zeph-memory/src/graph/types.rs b/crates/zeph-memory/src/graph/types.rs index 4fe11a226..80749a62a 100644 --- a/crates/zeph-memory/src/graph/types.rs +++ b/crates/zeph-memory/src/graph/types.rs @@ -19,6 +19,7 @@ pub use zeph_common::memory::EdgeType; /// Used by the LLM extractor to classify extracted named entities into coarse types. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)] #[serde(rename_all = "snake_case")] +#[non_exhaustive] pub enum EntityType { /// A human or AI agent. Person, @@ -299,9 +300,9 @@ pub fn evolved_weight(retrieval_count: i32, base_confidence: f32) -> f32 { pub fn edge_type_weight(et: EdgeType) -> f32 { match et { EdgeType::Causal => 1.2, - EdgeType::Semantic => 1.0, // baseline EdgeType::Temporal => 0.9, EdgeType::Entity => 0.8, + _ => 1.0, } } diff --git a/crates/zeph-memory/src/optical_forgetting.rs b/crates/zeph-memory/src/optical_forgetting.rs index 87856241d..64f0fdc7d 100644 --- a/crates/zeph-memory/src/optical_forgetting.rs +++ b/crates/zeph-memory/src/optical_forgetting.rs @@ -46,6 +46,7 @@ use crate::store::SqliteStore; /// how much of the original content is preserved. A message can be both /// `CompressionLevel::Episodic` and `ContentFidelity::Compressed`. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[non_exhaustive] pub enum ContentFidelity { /// Original full-fidelity content. Full, diff --git a/crates/zeph-memory/src/quality_gate.rs b/crates/zeph-memory/src/quality_gate.rs index 9acce96ed..e4ebca671 100644 --- a/crates/zeph-memory/src/quality_gate.rs +++ b/crates/zeph-memory/src/quality_gate.rs @@ -104,6 +104,7 @@ pub struct QualityScore { /// Reason for a quality gate rejection. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, serde::Serialize)] #[serde(rename_all = "snake_case")] +#[non_exhaustive] pub enum QualityRejectionReason { /// Cosine similarity to recent writes is too high — the content is redundant. Redundant, diff --git a/crates/zeph-memory/src/reasoning.rs b/crates/zeph-memory/src/reasoning.rs index 04000152f..ad34f24e3 100644 --- a/crates/zeph-memory/src/reasoning.rs +++ b/crates/zeph-memory/src/reasoning.rs @@ -77,6 +77,7 @@ Respond with the strategy text only — no headers, no lists, no markdown."; /// /// Stored as a `TEXT NOT NULL` column (`"success"` or `"failure"`). #[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[non_exhaustive] pub enum Outcome { /// The agent successfully completed the task. Success, diff --git a/crates/zeph-memory/src/semantic/mod.rs b/crates/zeph-memory/src/semantic/mod.rs index def8f8c0f..42be8f266 100644 --- a/crates/zeph-memory/src/semantic/mod.rs +++ b/crates/zeph-memory/src/semantic/mod.rs @@ -100,6 +100,7 @@ pub(crate) struct CachedCentroid { /// When `Enabled`, older memories receive lower scores based on the configured /// half-life. When `Disabled`, all memories are scored equally regardless of age. #[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] +#[non_exhaustive] pub enum TemporalDecay { /// Apply exponential decay: older memories score lower. Enabled, @@ -128,6 +129,7 @@ impl From for TemporalDecay { /// When `Enabled`, recall results are re-ranked to balance relevance and /// diversity using the configured lambda parameter. #[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] +#[non_exhaustive] pub enum MmrReranking { /// Apply MMR diversity re-ranking after initial vector search. Enabled, @@ -156,6 +158,7 @@ impl From for MmrReranking { /// When `Enabled`, each stored message receives an importance score that /// is blended into the recall ranking with the configured weight. #[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] +#[non_exhaustive] pub enum ImportanceScoring { /// Blend importance scores into recall ranking. Enabled, @@ -184,6 +187,7 @@ impl From for ImportanceScoring { /// When `Enabled`, queries containing first-person language are biased towards /// the stored user profile centroid to improve personalised recall. #[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] +#[non_exhaustive] pub enum QueryBiasCorrection { /// Shift first-person query embeddings towards the user profile centroid. #[default] @@ -212,6 +216,7 @@ impl From for QueryBiasCorrection { /// When `Enabled`, each graph edge traversed during recall receives a small /// weight increment (`hebbian_lr`), strengthening frequently-used associations. #[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] +#[non_exhaustive] pub enum HebbianReinforcement { /// Increment edge weights after each recall traversal. Enabled, diff --git a/crates/zeph-memory/src/semantic/recall.rs b/crates/zeph-memory/src/semantic/recall.rs index aef4cddc1..16b956e82 100644 --- a/crates/zeph-memory/src/semantic/recall.rs +++ b/crates/zeph-memory/src/semantic/recall.rs @@ -1221,10 +1221,6 @@ impl SemanticMemory { let kw = self.recall_fts5_raw(query, limit, conversation_id).await?; (kw, Vec::new()) } - MemoryRoute::Semantic => { - let vr = self.recall_vectors_raw(query, limit, filter).await?; - (Vec::new(), vr) - } MemoryRoute::Hybrid => { let kw = match self.recall_fts5_raw(query, limit, conversation_id).await { Ok(r) => r, @@ -1283,6 +1279,10 @@ impl SemanticMemory { let vr = self.recall_vectors_raw(query, limit, filter).await?; (kw, vr) } + _ => { + let vr = self.recall_vectors_raw(query, limit, filter).await?; + (Vec::new(), vr) + } }; tracing::debug!( @@ -1341,10 +1341,6 @@ impl SemanticMemory { let kw = self.recall_fts5_raw(query, limit, conversation_id).await?; (kw, Vec::new()) } - MemoryRoute::Semantic => { - let vr = self.recall_vectors_raw(query, limit, filter).await?; - (Vec::new(), vr) - } MemoryRoute::Hybrid => { let kw = match self.recall_fts5_raw(query, limit, conversation_id).await { Ok(r) => r, @@ -1387,6 +1383,10 @@ impl SemanticMemory { let vr = self.recall_vectors_raw(query, limit, filter).await?; (kw, vr) } + _ => { + let vr = self.recall_vectors_raw(query, limit, filter).await?; + (Vec::new(), vr) + } }; tracing::debug!( diff --git a/crates/zeph-memory/src/semantic/write_buffer.rs b/crates/zeph-memory/src/semantic/write_buffer.rs index 59064620d..3da8b3989 100644 --- a/crates/zeph-memory/src/semantic/write_buffer.rs +++ b/crates/zeph-memory/src/semantic/write_buffer.rs @@ -12,6 +12,7 @@ use std::collections::VecDeque; use crate::types::{ConversationId, MemoryTier}; /// A single buffered write operation waiting to be flushed to the store. +#[non_exhaustive] pub enum BufferedWrite { /// Save a message to the messages table. SaveMessage { diff --git a/crates/zeph-memory/src/shadow/mod.rs b/crates/zeph-memory/src/shadow/mod.rs index f58f5fa0c..72f59fd11 100644 --- a/crates/zeph-memory/src/shadow/mod.rs +++ b/crates/zeph-memory/src/shadow/mod.rs @@ -34,6 +34,7 @@ fn signal_type_label(t: AuditSignalType) -> &'static str { AuditSignalType::PromptInjectionPattern => "prompt_injection", AuditSignalType::ToolChainAnomaly => "tool_chain_anomaly", AuditSignalType::ConfidenceDrop => "confidence_drop", + _ => "unknown", } } @@ -42,6 +43,7 @@ fn severity_label(s: Severity) -> &'static str { Severity::Low => "low", Severity::Medium => "medium", Severity::High => "high", + _ => "unknown", } } @@ -150,11 +152,13 @@ impl TrajectoryRiskAccumulator { AuditSignalType::PromptInjectionPattern => config.signal_weights.prompt_injection, AuditSignalType::ToolChainAnomaly => config.signal_weights.tool_chain_anomaly, AuditSignalType::ConfidenceDrop => config.signal_weights.confidence_drop, + _ => 0.0, }; let severity_mult = match severity { Severity::Low => config.severity_multipliers.low, Severity::Medium => config.severity_multipliers.medium, Severity::High => config.severity_multipliers.high, + _ => 1.0, }; let raw_score = base_weight * severity_mult; diff --git a/crates/zeph-memory/src/store/agent_sessions.rs b/crates/zeph-memory/src/store/agent_sessions.rs index f037a8144..88449a8d7 100644 --- a/crates/zeph-memory/src/store/agent_sessions.rs +++ b/crates/zeph-memory/src/store/agent_sessions.rs @@ -13,6 +13,7 @@ use crate::error::MemoryError; /// Discriminant for the type of agent session. #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "lowercase")] +#[non_exhaustive] pub enum SessionKind { /// An interactive conversation session (CLI or TUI). Interactive, @@ -54,6 +55,7 @@ impl std::str::FromStr for SessionKind { /// Lifecycle status of an agent session. #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "lowercase")] +#[non_exhaustive] pub enum SessionStatus { /// Session is currently running. Active, @@ -103,6 +105,7 @@ impl std::str::FromStr for SessionStatus { /// Channel over which the session was initiated. #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "lowercase")] +#[non_exhaustive] pub enum SessionChannel { Cli, Tui, diff --git a/crates/zeph-memory/src/store/retrieval_failures.rs b/crates/zeph-memory/src/store/retrieval_failures.rs index 1531c1e3d..344db91e0 100644 --- a/crates/zeph-memory/src/store/retrieval_failures.rs +++ b/crates/zeph-memory/src/store/retrieval_failures.rs @@ -13,6 +13,7 @@ use zeph_db::sql; /// Classification of a memory retrieval failure event. #[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[non_exhaustive] pub enum RetrievalFailureType { /// No results were returned for the query. NoHit, diff --git a/crates/zeph-memory/src/store/trust.rs b/crates/zeph-memory/src/store/trust.rs index d05038029..40a16467a 100644 --- a/crates/zeph-memory/src/store/trust.rs +++ b/crates/zeph-memory/src/store/trust.rs @@ -12,6 +12,7 @@ use crate::error::MemoryError; /// Discriminant for the skill source stored in the trust table. #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "lowercase")] +#[non_exhaustive] pub enum SourceKind { Local, Hub, diff --git a/crates/zeph-memory/src/tiered_retrieval.rs b/crates/zeph-memory/src/tiered_retrieval.rs index da4457134..fba1546b2 100644 --- a/crates/zeph-memory/src/tiered_retrieval.rs +++ b/crates/zeph-memory/src/tiered_retrieval.rs @@ -48,6 +48,7 @@ use crate::types::{ConversationId, MessageId}; /// /// Maps to increasing levels of retrieval cost and depth. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[non_exhaustive] pub enum IntentClass { /// Fast profile/attribute lookup — keyword search, top-k = 3. ProfileLookup, @@ -61,8 +62,8 @@ impl IntentClass { fn from_route(route: MemoryRoute) -> Self { match route { MemoryRoute::Keyword | MemoryRoute::Episodic => Self::ProfileLookup, - MemoryRoute::Semantic | MemoryRoute::Hybrid => Self::TargetedRetrieval, MemoryRoute::Graph => Self::DeepReasoning, + _ => Self::TargetedRetrieval, } } diff --git a/crates/zeph-memory/src/types.rs b/crates/zeph-memory/src/types.rs index 9c5fa548d..e9811ec2f 100644 --- a/crates/zeph-memory/src/types.rs +++ b/crates/zeph-memory/src/types.rs @@ -6,6 +6,7 @@ /// Memory tier classification for the AOI four-layer architecture. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)] #[serde(rename_all = "lowercase")] +#[non_exhaustive] pub enum MemoryTier { /// Current conversation window. Virtual tier — not stored in the DB. Working, diff --git a/crates/zeph-memory/src/vector_store.rs b/crates/zeph-memory/src/vector_store.rs index e38a302d7..04f85c13d 100644 --- a/crates/zeph-memory/src/vector_store.rs +++ b/crates/zeph-memory/src/vector_store.rs @@ -17,6 +17,7 @@ use std::pin::Pin; /// Error type for [`VectorStore`] operations. #[derive(Debug, thiserror::Error)] +#[non_exhaustive] pub enum VectorStoreError { #[error("connection error: {0}")] Connection(String), @@ -70,6 +71,7 @@ pub struct FieldCondition { /// Value type in a [`FieldCondition`]. #[derive(Debug, Clone)] +#[non_exhaustive] pub enum FieldValue { /// Exact integer match. Integer(i64), diff --git a/crates/zeph-orchestration/src/dag.rs b/crates/zeph-orchestration/src/dag.rs index 1d54645e6..be42edee1 100644 --- a/crates/zeph-orchestration/src/dag.rs +++ b/crates/zeph-orchestration/src/dag.rs @@ -297,6 +297,10 @@ pub fn propagate_failure( graph.status = GraphStatus::Paused; Vec::new() } + _ => { + graph.status = GraphStatus::Failed; + Vec::new() + } } } diff --git a/crates/zeph-orchestration/src/plan_cache.rs b/crates/zeph-orchestration/src/plan_cache.rs index fadce03de..b7cdaa468 100644 --- a/crates/zeph-orchestration/src/plan_cache.rs +++ b/crates/zeph-orchestration/src/plan_cache.rs @@ -545,7 +545,7 @@ async fn adapt_plan( ToolPolicy::DenyList(excluded) => { format!("all except: [{}]", excluded.join(", ")) } - ToolPolicy::InheritAll => "all".to_string(), + _ => "all".to_string(), }; format!( "- name: \"{}\", description: \"{}\", tools: [{}]", diff --git a/crates/zeph-orchestration/src/planner.rs b/crates/zeph-orchestration/src/planner.rs index 7296e87f4..fd6165033 100644 --- a/crates/zeph-orchestration/src/planner.rs +++ b/crates/zeph-orchestration/src/planner.rs @@ -236,7 +236,7 @@ fn build_prompt(goal: &str, agents: &[SubAgentDef], max_tasks: u32) -> Vec { format!("all except: [{}]", excluded.join(", ")) } - ToolPolicy::InheritAll => "all".to_string(), + _ => "all".to_string(), }; format!( "- name: \"{}\", description: \"{}\", tools: [{}]", diff --git a/crates/zeph-orchestration/src/router.rs b/crates/zeph-orchestration/src/router.rs index 1df317248..3a0e88261 100644 --- a/crates/zeph-orchestration/src/router.rs +++ b/crates/zeph-orchestration/src/router.rs @@ -130,7 +130,7 @@ fn agent_has_tool(def: &SubAgentDef, tool_name: &str) -> bool { match &def.tools { ToolPolicy::AllowList(allowed) => allowed.iter().any(|t| t == tool_name), ToolPolicy::DenyList(denied) => !denied.iter().any(|t| t == tool_name), - ToolPolicy::InheritAll => true, + _ => true, } } diff --git a/crates/zeph-skills/src/scanner.rs b/crates/zeph-skills/src/scanner.rs index 68207e26b..2c1632d06 100644 --- a/crates/zeph-skills/src/scanner.rs +++ b/crates/zeph-skills/src/scanner.rs @@ -76,7 +76,6 @@ pub fn check_capability_escalation( trust_level: SkillTrustLevel, ) -> Vec { match trust_level { - SkillTrustLevel::Trusted | SkillTrustLevel::Verified => Vec::new(), SkillTrustLevel::Quarantined => allowed_tools .iter() .filter(|tool| { @@ -88,6 +87,7 @@ pub fn check_capability_escalation( .collect(), // Blocked skills must not declare any tools — all are violations. SkillTrustLevel::Blocked => allowed_tools.to_vec(), + _ => Vec::new(), } } diff --git a/crates/zeph-subagent/src/def.rs b/crates/zeph-subagent/src/def.rs index 8eb5bed65..ebd725b59 100644 --- a/crates/zeph-subagent/src/def.rs +++ b/crates/zeph-subagent/src/def.rs @@ -760,7 +760,7 @@ impl<'a> WritableToolPolicy<'a> { deny: Some(v), except, }, - ToolPolicy::InheritAll => Self { + _ => Self { allow: None, deny: None, except, diff --git a/crates/zeph-subagent/src/filter.rs b/crates/zeph-subagent/src/filter.rs index fee83f2e5..d7b2ff1ec 100644 --- a/crates/zeph-subagent/src/filter.rs +++ b/crates/zeph-subagent/src/filter.rs @@ -123,9 +123,9 @@ impl FilteredToolExecutor { return false; } match &self.policy { - ToolPolicy::InheritAll => true, ToolPolicy::AllowList(list) => list.iter().any(|t| normalize_tool_id(t) == normalized), ToolPolicy::DenyList(list) => !list.iter().any(|t| normalize_tool_id(t) == normalized), + _ => true, } } } diff --git a/crates/zeph-subagent/src/hooks.rs b/crates/zeph-subagent/src/hooks.rs index 257eff720..c4bc1996e 100644 --- a/crates/zeph-subagent/src/hooks.rs +++ b/crates/zeph-subagent/src/hooks.rs @@ -384,6 +384,7 @@ async fn fire_single_hook( }), } } + _ => Ok(HookOutput::default()), } } diff --git a/crates/zeph-subagent/src/manager.rs b/crates/zeph-subagent/src/manager.rs index 02f908ba7..bf50c0e91 100644 --- a/crates/zeph-subagent/src/manager.rs +++ b/crates/zeph-subagent/src/manager.rs @@ -606,7 +606,6 @@ fn apply_context_injection( use zeph_config::ContextInjectionMode; match mode { - ContextInjectionMode::None => task_prompt.to_owned(), ContextInjectionMode::LastAssistantTurn => { let last_assistant = parent_messages .iter() @@ -631,6 +630,7 @@ fn apply_context_injection( format!("Parent agent context: {summary}\n\n{task_prompt}") } } + _ => task_prompt.to_owned(), } } diff --git a/crates/zeph-subagent/src/memory.rs b/crates/zeph-subagent/src/memory.rs index 26d587b47..e1b93744f 100644 --- a/crates/zeph-subagent/src/memory.rs +++ b/crates/zeph-subagent/src/memory.rs @@ -95,6 +95,13 @@ pub fn resolve_memory_dir(scope: MemoryScope, agent_name: &str) -> Result { + let home = dirs::home_dir().ok_or_else(|| SubAgentError::Memory { + name: agent_name.to_owned(), + reason: "home directory unavailable".to_owned(), + })?; + home.join(".zeph").join("agent-memory").join(agent_name) + } }; Ok(dir) } diff --git a/crates/zeph-tools/src/audit.rs b/crates/zeph-tools/src/audit.rs index d378085b3..111fd7361 100644 --- a/crates/zeph-tools/src/audit.rs +++ b/crates/zeph-tools/src/audit.rs @@ -287,12 +287,12 @@ impl AuditLogger { let file = tokio::fs::File::from_std(std_file); AuditDestination::File(tokio::sync::Mutex::new(file)) } - CfgDest::Stdout | CfgDest::Stderr => AuditDestination::Stdout, CfgDest::File(path) => { let std_file = zeph_common::fs_secure::append_private(path)?; let file = tokio::fs::File::from_std(std_file); AuditDestination::File(tokio::sync::Mutex::new(file)) } + _ => AuditDestination::Stdout, }; Ok(Self { destination }) diff --git a/crates/zeph-tools/src/executor.rs b/crates/zeph-tools/src/executor.rs index 2cd2eb721..35984a8b5 100644 --- a/crates/zeph-tools/src/executor.rs +++ b/crates/zeph-tools/src/executor.rs @@ -1431,7 +1431,7 @@ mod tests { crate::SkillTrustLevel::Trusted => 0u8, crate::SkillTrustLevel::Verified => 1, crate::SkillTrustLevel::Quarantined => 2, - crate::SkillTrustLevel::Blocked => 3, + _ => 3, }; self.0.store(v, Ordering::Relaxed); } diff --git a/crates/zeph-tools/src/permissions.rs b/crates/zeph-tools/src/permissions.rs index faf9563f4..ef3cbaad7 100644 --- a/crates/zeph-tools/src/permissions.rs +++ b/crates/zeph-tools/src/permissions.rs @@ -74,6 +74,7 @@ impl PermissionPolicy { } PermissionAction::Ask } + _ => PermissionAction::Deny, } } diff --git a/crates/zeph-tools/src/policy.rs b/crates/zeph-tools/src/policy.rs index 3a265b82f..e88567b3d 100644 --- a/crates/zeph-tools/src/policy.rs +++ b/crates/zeph-tools/src/policy.rs @@ -273,6 +273,9 @@ impl PolicyEnforcer { DefaultEffect::Deny => PolicyDecision::Deny { trace: "default: deny (no matching rules)".to_owned(), }, + _ => PolicyDecision::Deny { + trace: "default: deny (unknown effect)".to_owned(), + }, } } } diff --git a/crates/zeph-tools/src/scope.rs b/crates/zeph-tools/src/scope.rs index 37c23e231..90fa31d54 100644 --- a/crates/zeph-tools/src/scope.rs +++ b/crates/zeph-tools/src/scope.rs @@ -282,11 +282,11 @@ impl ToolScope { fn is_strict_pattern(pattern: &str, strictness: PatternStrictness) -> bool { match strictness { PatternStrictness::Strict => true, - PatternStrictness::Permissive => false, PatternStrictness::ProvisionalForDynamicNamespaces => { // Strict for builtin: and skill:; provisional for mcp:, acp:, a2a: pattern.starts_with("builtin:") || pattern.starts_with("skill:") } + _ => false, } } diff --git a/crates/zeph-tools/src/trust_gate.rs b/crates/zeph-tools/src/trust_gate.rs index 63766afa0..88a9393d8 100644 --- a/crates/zeph-tools/src/trust_gate.rs +++ b/crates/zeph-tools/src/trust_gate.rs @@ -35,7 +35,7 @@ fn trust_to_u8(level: SkillTrustLevel) -> u8 { SkillTrustLevel::Trusted => 0, SkillTrustLevel::Verified => 1, SkillTrustLevel::Quarantined => 2, - SkillTrustLevel::Blocked => 3, + _ => 3, } } @@ -111,14 +111,14 @@ impl TrustGateExecutor { command: "all tools blocked (trust=blocked)".to_owned(), }); } - SkillTrustLevel::Quarantined => { - if is_quarantine_denied(tool_id) || self.is_mcp_tool(tool_id) { - return Err(ToolError::Blocked { - command: format!("{tool_id} denied (trust=quarantined)"), - }); - } + SkillTrustLevel::Quarantined + if is_quarantine_denied(tool_id) || self.is_mcp_tool(tool_id) => + { + return Err(ToolError::Blocked { + command: format!("{tool_id} denied (trust=quarantined)"), + }); } - SkillTrustLevel::Trusted | SkillTrustLevel::Verified => {} + _ => {} } // PermissionPolicy was designed for the bash tool. In Supervised mode, tools @@ -136,7 +136,7 @@ impl TrustGateExecutor { PermissionAction::Ask => Err(ToolError::ConfirmationRequired { command: input.to_owned(), }), - PermissionAction::Deny => Err(ToolError::Blocked { + _ => Err(ToolError::Blocked { command: input.to_owned(), }), } @@ -157,7 +157,7 @@ impl ToolExecutor for TrustGateExecutor { ), }); } - SkillTrustLevel::Trusted | SkillTrustLevel::Verified => {} + _ => {} } self.inner.execute(response).await } @@ -173,7 +173,7 @@ impl ToolExecutor for TrustGateExecutor { ), }); } - SkillTrustLevel::Trusted | SkillTrustLevel::Verified => {} + _ => {} } self.inner.execute_confirmed(response).await } @@ -208,16 +208,15 @@ impl ToolExecutor for TrustGateExecutor { command: "all tools blocked (trust=blocked)".to_owned(), }); } - SkillTrustLevel::Quarantined => { + SkillTrustLevel::Quarantined if is_quarantine_denied(call.tool_id.as_str()) - || self.is_mcp_tool(call.tool_id.as_str()) - { - return Err(ToolError::Blocked { - command: format!("{} denied (trust=quarantined)", call.tool_id), - }); - } + || self.is_mcp_tool(call.tool_id.as_str()) => + { + return Err(ToolError::Blocked { + command: format!("{} denied (trust=quarantined)", call.tool_id), + }); } - SkillTrustLevel::Trusted | SkillTrustLevel::Verified => {} + _ => {} } self.inner.execute_tool_call_confirmed(call).await } diff --git a/crates/zeph-tui/src/widgets/fleet.rs b/crates/zeph-tui/src/widgets/fleet.rs index 6233340fc..90a839a90 100644 --- a/crates/zeph-tui/src/widgets/fleet.rs +++ b/crates/zeph-tui/src/widgets/fleet.rs @@ -27,6 +27,7 @@ fn status_color(status: SessionStatus) -> Color { SessionStatus::Failed => Color::Red, SessionStatus::Cancelled => Color::Yellow, SessionStatus::Unknown => Color::Magenta, + _ => Color::White, } } diff --git a/crates/zeph-tui/src/widgets/memory.rs b/crates/zeph-tui/src/widgets/memory.rs index 95472c536..0e62e5724 100644 --- a/crates/zeph-tui/src/widgets/memory.rs +++ b/crates/zeph-tui/src/widgets/memory.rs @@ -16,6 +16,7 @@ fn cat_label(cat: ProbeCategory) -> &'static str { ProbeCategory::Artifact => "Art", ProbeCategory::Continuation => "Con", ProbeCategory::Decision => "Dec", + _ => "Unk", } } @@ -28,6 +29,7 @@ fn render_probe_last_line<'a>(metrics: &'a MetricsSnapshot, lines: &mut Vec ("SoftFail", Color::Yellow), ProbeVerdict::HardFail => ("HardFail", Color::Red), ProbeVerdict::Error => ("Error", Color::Gray), + _ => ("Unknown", Color::White), }; let score_str = metrics .last_probe_score diff --git a/crates/zeph-tui/src/widgets/subagents.rs b/crates/zeph-tui/src/widgets/subagents.rs index 251070eb9..69ff85574 100644 --- a/crates/zeph-tui/src/widgets/subagents.rs +++ b/crates/zeph-tui/src/widgets/subagents.rs @@ -751,7 +751,7 @@ fn render_detail(defs: &[SubAgentDef], index: usize, theme: &Theme, frame: &mut let tools_str = match &def.tools { ToolPolicy::AllowList(v) => format!("allow {v:?}"), ToolPolicy::DenyList(v) => format!("deny {v:?}"), - ToolPolicy::InheritAll => "inherit_all".to_owned(), + _ => "all".to_owned(), }; let except_str = if def.disallowed_tools.is_empty() { String::new() diff --git a/crates/zeph-tui/src/widgets/task_registry.rs b/crates/zeph-tui/src/widgets/task_registry.rs index fcc6aa5f0..0f73284bd 100644 --- a/crates/zeph-tui/src/widgets/task_registry.rs +++ b/crates/zeph-tui/src/widgets/task_registry.rs @@ -37,6 +37,7 @@ fn status_color(status: &TaskStatus) -> Color { TaskStatus::Completed => Color::Green, TaskStatus::Failed { .. } => Color::Red, TaskStatus::Aborted => Color::DarkGray, + _ => Color::White, } } @@ -47,6 +48,7 @@ fn format_status(status: &TaskStatus) -> String { TaskStatus::Completed => "Completed".to_owned(), TaskStatus::Failed { .. } => "Failed".to_owned(), TaskStatus::Aborted => "Aborted".to_owned(), + _ => "Unknown".to_owned(), } } diff --git a/src/agent_setup.rs b/src/agent_setup.rs index 4014779cc..7103f83d6 100644 --- a/src/agent_setup.rs +++ b/src/agent_setup.rs @@ -1434,7 +1434,7 @@ pub(crate) fn apply_mcp_discovery( let strategy = match discovery.strategy { ToolDiscoveryStrategyConfig::Embedding => ToolDiscoveryStrategy::Embedding, ToolDiscoveryStrategyConfig::Llm => ToolDiscoveryStrategy::Llm, - ToolDiscoveryStrategyConfig::None => ToolDiscoveryStrategy::None, + _ => ToolDiscoveryStrategy::None, }; if strategy == ToolDiscoveryStrategy::Llm { diff --git a/src/bootstrap/mcp.rs b/src/bootstrap/mcp.rs index 1e45ca3ae..c55a61bd8 100644 --- a/src/bootstrap/mcp.rs +++ b/src/bootstrap/mcp.rs @@ -105,6 +105,7 @@ pub fn create_mcp_manager_with_vault( OAuthTokenStorage::Memory => { Arc::new(rmcp::transport::auth::InMemoryCredentialStore::new()) } + _ => Arc::new(rmcp::transport::auth::InMemoryCredentialStore::new()), }; manager = manager.with_oauth_credential_store(s.id.clone(), store); } diff --git a/src/bootstrap/mod.rs b/src/bootstrap/mod.rs index 99d916b5e..bf1b22cba 100644 --- a/src/bootstrap/mod.rs +++ b/src/bootstrap/mod.rs @@ -208,7 +208,7 @@ impl AppBuilder { })?; Some(ops) } - zeph_core::config::VectorBackend::Sqlite => None, + _ => None, }; Ok(Self { @@ -399,6 +399,16 @@ impl AppBuilder { .await .map_err(|e| BootstrapError::Memory(e.to_string()))? } + _ => SemanticMemory::with_sqlite_backend_and_pool_size( + db_path, + provider.clone(), + &embed_model, + self.config.memory.semantic.vector_weight, + self.config.memory.semantic.keyword_weight, + self.config.memory.sqlite_pool_size, + ) + .await + .map_err(|e| BootstrapError::Memory(e.to_string()))?, }; memory = memory.with_ranking_options( diff --git a/src/commands/agents.rs b/src/commands/agents.rs index fb3ac7835..04cbfebc0 100644 --- a/src/commands/agents.rs +++ b/src/commands/agents.rs @@ -108,6 +108,7 @@ fn handle_show(name: &str, config_path: Option<&Path>) -> anyhow::Result<()> { ToolPolicy::AllowList(v) => format!("allow {v:?}"), ToolPolicy::DenyList(v) => format!("deny {v:?}"), ToolPolicy::InheritAll => "inherit_all".to_owned(), + _ => "all".to_owned(), }; if def.disallowed_tools.is_empty() { println!("Tools: {tools_str}"); diff --git a/src/commands/project.rs b/src/commands/project.rs index 918aa622a..9850c3efd 100644 --- a/src/commands/project.rs +++ b/src/commands/project.rs @@ -217,6 +217,7 @@ async fn run_purge( let backend_label = match backend { VectorBackend::Qdrant => "qdrant", VectorBackend::Sqlite => "sqlite", + _ => "unknown", }; if dry_run { @@ -450,6 +451,17 @@ impl PurgeEngine<'_> { }], }; } + _ => { + return PurgeCategory { + name: "Audit log", + items: vec![PurgeItem { + path_or_desc: "(unknown destination)".to_owned(), + path: None, + bytes: 0, + note: None, + }], + }; + } }; PurgeCategory { name: "Audit log", @@ -471,30 +483,25 @@ impl PurgeEngine<'_> { use zeph_memory::qdrant_ops::QdrantOps; println!(" Qdrant collections:"); - match backend { - VectorBackend::Sqlite => { - println!( - " (skipped — vector_backend is sqlite; vectors stored in SQLite DB above)" - ); - } - VectorBackend::Qdrant => { - let api_key = config - .memory - .qdrant_api_key - .as_ref() - .map(|s| s.expose().to_owned()); - let ops = match QdrantOps::new(&config.memory.qdrant_url, api_key.as_deref()) { - Ok(o) => o, - Err(e) => { - println!(" (cannot connect to Qdrant: {e})"); - return; - } - }; - for name in qdrant_collections(config) { - let exists = ops.collection_exists(&name).await.unwrap_or(false); - let status = if exists { "exists" } else { "not found" }; - println!(" {name:<40} ({status})"); + if matches!(backend, VectorBackend::Sqlite) { + println!(" (skipped — vector_backend is sqlite; vectors stored in SQLite DB above)"); + } else { + let api_key = config + .memory + .qdrant_api_key + .as_ref() + .map(|s| s.expose().to_owned()); + let ops = match QdrantOps::new(&config.memory.qdrant_url, api_key.as_deref()) { + Ok(o) => o, + Err(e) => { + println!(" (cannot connect to Qdrant: {e})"); + return; } + }; + for name in qdrant_collections(config) { + let exists = ops.collection_exists(&name).await.unwrap_or(false); + let status = if exists { "exists" } else { "not found" }; + println!(" {name:<40} ({status})"); } } println!(); @@ -509,75 +516,65 @@ impl PurgeEngine<'_> { use zeph_config::VectorBackend; use zeph_memory::qdrant_ops::QdrantOps; - match backend { - VectorBackend::Sqlite => { - println!( - " Qdrant: skipped (vector_backend = sqlite; vectors removed with SQLite DB)" - ); - 0 + if matches!(backend, VectorBackend::Sqlite) { + println!(" Qdrant: skipped (vector_backend = sqlite; vectors removed with SQLite DB)"); + return 0; + } + let api_key = config + .memory + .qdrant_api_key + .as_ref() + .map(|s| s.expose().to_owned()); + let ops = match QdrantOps::new(&config.memory.qdrant_url, api_key.as_deref()) { + Ok(o) => o, + Err(e) => { + eprintln!(" Warning: cannot connect to Qdrant: {e}"); + return 0; } - VectorBackend::Qdrant => { - let api_key = config - .memory - .qdrant_api_key - .as_ref() - .map(|s| s.expose().to_owned()); - let ops = match QdrantOps::new(&config.memory.qdrant_url, api_key.as_deref()) { - Ok(o) => o, - Err(e) => { - eprintln!(" Warning: cannot connect to Qdrant: {e}"); - return 0; - } - }; + }; - // A-3: use buffer_unordered for concurrent deletion (worst-case 10 collections). - let results: Vec<(String, bool)> = futures::stream::iter(qdrant_collections( - config, - )) - .map(|name| { - let ops = &ops; - async move { - // M-2: check existence before attempting delete to avoid noisy warnings. - let exists = ops.collection_exists(&name).await.unwrap_or(true); - if !exists { - return (name, false); + // A-3: use buffer_unordered for concurrent deletion (worst-case 10 collections). + let results: Vec<(String, bool)> = futures::stream::iter(qdrant_collections(config)) + .map(|name| { + let ops = &ops; + async move { + // M-2: check existence before attempting delete to avoid noisy warnings. + let exists = ops.collection_exists(&name).await.unwrap_or(true); + if !exists { + return (name, false); + } + let deleted = tokio::time::timeout( + std::time::Duration::from_secs(10), + ops.delete_collection(&name), + ) + .await; + match deleted { + Ok(Ok(())) => (name, true), + Ok(Err(e)) => { + eprintln!(" Warning: failed to delete Qdrant collection {name}: {e}"); + (name, false) } - let deleted = tokio::time::timeout( - std::time::Duration::from_secs(10), - ops.delete_collection(&name), - ) - .await; - match deleted { - Ok(Ok(())) => (name, true), - Ok(Err(e)) => { - eprintln!( - " Warning: failed to delete Qdrant collection {name}: {e}" - ); - (name, false) - } - Err(_) => { - eprintln!(" Warning: timeout deleting Qdrant collection {name}"); - (name, false) - } + Err(_) => { + eprintln!(" Warning: timeout deleting Qdrant collection {name}"); + (name, false) } } - }) - .buffer_unordered(10) - .collect() - .await; - - let mut deleted = 0usize; - for (name, success) in results { - if success { - println!(" Deleted Qdrant collection: {name}"); - deleted += 1; - } else { - println!(" Qdrant collection {name}: not found or skipped"); - } } - deleted + }) + .buffer_unordered(10) + .collect() + .await; + + let mut deleted = 0usize; + for (name, success) in results { + if success { + println!(" Deleted Qdrant collection: {name}"); + deleted += 1; + } else { + println!(" Qdrant collection {name}: not found or skipped"); } } + deleted } } @@ -642,9 +639,10 @@ fn print_dry_run_report( println!(); } - let qdrant_note = match backend { - zeph_config::VectorBackend::Qdrant => " (+ Qdrant collections)", - zeph_config::VectorBackend::Sqlite => "", + let qdrant_note = if matches!(backend, zeph_config::VectorBackend::Qdrant) { + " (+ Qdrant collections)" + } else { + "" }; println!( "Total: ~{} would be freed{}", diff --git a/src/runner.rs b/src/runner.rs index f1cd8698a..29af2cabb 100644 --- a/src/runner.rs +++ b/src/runner.rs @@ -74,7 +74,7 @@ impl zeph_tools::PolicyLlmClient for AdversarialPolicyLlmAdapter { zeph_llm::provider::Message::from_legacy( match m.role { zeph_tools::PolicyRole::System => zeph_llm::provider::Role::System, - zeph_tools::PolicyRole::User => zeph_llm::provider::Role::User, + _ => zeph_llm::provider::Role::User, }, m.content.clone(), ) @@ -352,6 +352,19 @@ async fn run_configured_acp_autostart(cli: &Cli, transport: AcpTransport) -> any )) .await } + #[cfg(feature = "acp-http")] + _ => { + Box::pin(run_acp_server( + config_path.as_deref(), + vault_backend.as_deref(), + vault_key.as_deref(), + vault_path.as_deref(), + Vec::new(), + Vec::new(), + None, + )) + .await + } } } @@ -1093,10 +1106,10 @@ pub(crate) async fn run(cli: Cli) -> anyhow::Result<()> { let source_kind = source_kind.clone(); let initial_level = match source_kind { zeph_memory::store::SourceKind::Bundled => &trust_cfg.bundled_level, - zeph_memory::store::SourceKind::Hub => &trust_cfg.default_level, zeph_memory::store::SourceKind::Local | zeph_memory::store::SourceKind::File => { &trust_cfg.local_level } + _ => &trust_cfg.default_level, }; let Some(current_hash) = maybe_hash else { tracing::warn!("failed to compute hash for '{}'", meta.name); @@ -1292,6 +1305,7 @@ pub(crate) async fn run(cli: Cli) -> anyhow::Result<()> { AnyChannel::Discord(_) => "discord", #[cfg(feature = "slack")] AnyChannel::Slack(_) => "slack", + _ => "unknown", }, } .to_owned(); @@ -1304,6 +1318,7 @@ pub(crate) async fn run(cli: Cli) -> anyhow::Result<()> { AnyChannel::Discord(_) => "discord", #[cfg(feature = "slack")] AnyChannel::Slack(_) => "slack", + _ => "unknown", } .to_owned(); diff --git a/src/scheduler.rs b/src/scheduler.rs index 3ce1f1262..ac3fcedf8 100644 --- a/src/scheduler.rs +++ b/src/scheduler.rs @@ -208,6 +208,7 @@ pub(crate) fn load_config_tasks( ScheduledTaskKind::UpdateCheck => TaskKind::UpdateCheck, ScheduledTaskKind::Experiment => TaskKind::Experiment, ScheduledTaskKind::Custom(s) => TaskKind::Custom(s.clone()), + _ => continue, }; let mode = if let Some(cron_expr) = &task.cron { diff --git a/src/tracing_init.rs b/src/tracing_init.rs index 34403cac5..a0443268e 100644 --- a/src/tracing_init.rs +++ b/src/tracing_init.rs @@ -193,7 +193,7 @@ pub(crate) fn init_tracing( let rotation = match logging.rotation { LogRotation::Daily => Rotation::DAILY, LogRotation::Hourly => Rotation::HOURLY, - LogRotation::Never => Rotation::NEVER, + _ => Rotation::NEVER, }; match RollingFileAppender::builder() .rotation(rotation)