Summary
KernelHandle trait has ~40 methods returning Result<_, String>. The String destroys all structured error info at the most-trafficked seam between runtime and kernel. Downstream code resorts to .contains("not found") substring matches to map errors back to user-visible categories — the very anti-pattern LlmError::failover_reason was written to escape.
Location
crates/librefang-kernel-handle/src/lib.rs:30-651
async fn spawn_agent(...) -> Result<(String, String), String>;
async fn send_to_agent(...) -> Result<String, String>;
async fn task_post(...) -> Result<String, String>;
async fn knowledge_add_entity(...) -> Result<String, String>;
async fn run_workflow(...) -> Result<(String, String), String>;
// 30+ more, all `Result<_, String>`
Why it bites
librefang-types::error::LibreFangError already exists as the official structured taxonomy (AgentNotFound, CapabilityDenied, QuotaExceeded, InvalidState, ShuttingDown, AuthDenied, …). Runtime cannot distinguish "agent not found" (404) from "kernel shutting down" (retry later) from "capability denied" (403) without parsing English error strings. Adding new categories (e.g. RateLimited, BudgetExhausted) requires churning string-matching audits.
Fix
- Introduce
pub type KernelResult<T> = Result<T, LibreFangError>; in librefang-types.
- Mark
LibreFangError #[non_exhaustive].
- Migrate hot methods first:
send_to_agent, spawn_agent, task_*, request_approval.
- Provide a transitional
From<LibreFangError> for String so call sites compile during the rollout.
The trait is the single chokepoint for runtime↔kernel; this is the right place to fix it once.
Summary
KernelHandletrait has ~40 methods returningResult<_, String>. TheStringdestroys all structured error info at the most-trafficked seam between runtime and kernel. Downstream code resorts to.contains("not found")substring matches to map errors back to user-visible categories — the very anti-patternLlmError::failover_reasonwas written to escape.Location
crates/librefang-kernel-handle/src/lib.rs:30-651Why it bites
librefang-types::error::LibreFangErroralready exists as the official structured taxonomy (AgentNotFound,CapabilityDenied,QuotaExceeded,InvalidState,ShuttingDown,AuthDenied, …). Runtime cannot distinguish "agent not found" (404) from "kernel shutting down" (retry later) from "capability denied" (403) without parsing English error strings. Adding new categories (e.g.RateLimited,BudgetExhausted) requires churning string-matching audits.Fix
pub type KernelResult<T> = Result<T, LibreFangError>;inlibrefang-types.LibreFangError#[non_exhaustive].send_to_agent,spawn_agent,task_*,request_approval.From<LibreFangError> for Stringso call sites compile during the rollout.The trait is the single chokepoint for runtime↔kernel; this is the right place to fix it once.