//! Central deny-by-default authorization, approval, budget, and audit gateway. #![allow(clippy::missing_errors_doc)] // Public fallible APIs share PolicyError/PolicyReasonCode. use crate::backend::AuthorizedToolBackend; use crate::llm::ToolDefinition; use crate::tool_loop::{ToolExecution, ToolExecutor, ToolFuture}; use crate::types::{ BoundedText, MAX_IDENTIFIER_BYTES, MAX_MESSAGE_BYTES, ProposedToolCall, ToolCallOutcome, }; use libremetaverse_types::UUID; use libremetaverse_types::compat::CancellationToken; use serde_json::{Map, Value}; use sha2::{Digest as _, Sha256}; use std::collections::{BTreeMap, BTreeSet, VecDeque}; use std::error::Error; use std::fmt; use std::sync::{Arc, Mutex}; use std::time::{SystemTime, UNIX_EPOCH}; const MAX_POLICY_TOOLS: usize = 64; const MAX_AUTHORIZED_AVATARS: usize = 1_024; const MAX_AUDIT_RECORDS: usize = 4_096; const MAX_APPROVALS: usize = 4_096; const MAX_SCHEDULER_GRANTS: usize = 1_024; const MAX_BUDGET_TOOL_CALLS: u64 = 1_000_000; const MAX_BUDGET_UPLOAD_BYTES: u64 = 1024 * 1024 * 1024; const MAX_BUDGET_INVENTORY_OPERATIONS: u64 = 1_000_000; const MAX_BUDGET_MOVEMENT_MILLIMETERS: u64 = 1_000_000_000_000; const MAX_BUDGET_BUILD_PRIMS: u64 = 1_000_000; const MAX_OPERATOR_PRINCIPAL_BYTES: usize = 96; #[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)] pub enum OriginClass { PublicChat, UnprivilegedIm, AuthorizedIm, LocalOperator, InternalScheduler, } #[derive(Clone, Debug, Eq, PartialEq)] enum OriginKind { PublicChat(UUID), InstantMessage(UUID), LocalOperator(AuthenticatedPrincipal), InternalScheduler(SchedulerGrantId), } /// Request origin whose privileged variants have no public constructor. #[derive(Clone, Debug, Eq, PartialEq)] pub struct ActionOrigin(OriginKind); impl ActionOrigin { #[must_use] pub const fn public_chat(avatar_id: UUID) -> Self { Self(OriginKind::PublicChat(avatar_id)) } #[must_use] pub const fn instant_message(avatar_id: UUID) -> Self { Self(OriginKind::InstantMessage(avatar_id)) } } /// Principal produced only by the authenticated control-plane implementation. #[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)] pub struct AuthenticatedPrincipal(BoundedText); impl AuthenticatedPrincipal { pub(crate) fn from_authenticated_control( principal: impl Into, ) -> Result { let principal = BoundedText::new("policy.operator_principal", principal)?; if !principal.chars().all(|character| { character.is_ascii_alphanumeric() || matches!(character, '.' | '_' | '-' | ':') }) { return Err(PolicyError::InvalidPrincipal); } Ok(Self(principal)) } #[must_use] pub fn as_str(&self) -> &str { self.0.as_str() } } #[derive(Clone, Debug, Eq, PartialEq)] pub struct PolicyRequestContext { origin: ActionOrigin, session_id: BoundedText, correlation_id: BoundedText, } impl PolicyRequestContext { pub fn new( origin: ActionOrigin, session_id: impl Into, correlation_id: impl Into, ) -> Result { Ok(Self { origin, session_id: policy_identifier("policy.session_id", session_id)?, correlation_id: policy_identifier("policy.correlation_id", correlation_id)?, }) } pub fn authenticated_operator( principal: AuthenticatedPrincipal, session_id: impl Into, correlation_id: impl Into, ) -> Result { Self::new( ActionOrigin(OriginKind::LocalOperator(principal)), session_id, correlation_id, ) } pub fn scheduler( grant: SchedulerGrantId, session_id: impl Into, correlation_id: impl Into, ) -> Result { Self::new( ActionOrigin(OriginKind::InternalScheduler(grant)), session_id, correlation_id, ) } } #[derive(Clone, Debug, Eq, PartialEq)] enum PrincipalKey { Avatar(UUID), Operator(AuthenticatedPrincipal), } impl Ord for PrincipalKey { fn cmp(&self, other: &Self) -> std::cmp::Ordering { self.audit_label().cmp(&other.audit_label()) } } impl PartialOrd for PrincipalKey { fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } } impl PrincipalKey { fn audit_label(&self) -> String { match self { Self::Avatar(id) => format!("avatar:{id}"), Self::Operator(id) => format!("operator:{}", id.as_str()), } } const fn avatar_id(&self) -> Option { match self { Self::Avatar(id) => Some(*id), Self::Operator(_) => None, } } } #[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)] pub enum Capability { Informational, PublicLslRequest, InventoryMutation, Movement, Build, ObjectMutation, } #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub enum Risk { ReadOnly, InventoryMutation, Movement, Build, ObjectMutation, CurrencySpend, EstateOrParcelChange, PermanentDelete, ArbitraryInventoryAcceptance, GeneratedCodeExecution, } impl Risk { const fn forbidden_in_milestone(self) -> bool { matches!( self, Self::CurrencySpend | Self::EstateOrParcelChange | Self::PermanentDelete | Self::ArbitraryInventoryAcceptance | Self::GeneratedCodeExecution ) } const fn is_mutating(self) -> bool { !matches!(self, Self::ReadOnly) } } #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub enum Idempotency { Idempotent, NonIdempotent, } #[derive(Clone, Debug, Eq, PartialEq)] pub struct AllowedOrigins(BTreeSet); impl AllowedOrigins { pub fn new(origins: impl IntoIterator) -> Result { let origins = origins.into_iter().collect::>(); if origins.is_empty() || origins.len() > 5 { return Err(PolicyError::InvalidRegistration); } Ok(Self(origins)) } fn contains(&self, origin: OriginClass) -> bool { self.0.contains(&origin) } } #[derive(Clone, Copy, Debug, Default, Eq, PartialEq)] pub struct ResourceCost { pub tool_calls: u64, pub linden_dollars: u64, pub upload_bytes: u64, pub inventory_operations: u64, pub movement_millimeters: u64, pub build_prims: u64, } /// Secret-free operator projection of one pending approval. #[derive(Clone, Debug, Eq, PartialEq)] pub struct PendingApprovalMetadata { pub id: ApprovalId, pub principal: String, pub tool: String, pub expires_at: u64, pub cost: ResourceCost, } impl ResourceCost { #[must_use] pub const fn one_call() -> Self { Self { tool_calls: 1, linden_dollars: 0, upload_bytes: 0, inventory_operations: 0, movement_millimeters: 0, build_prims: 0, } } fn normalized(mut self) -> Self { self.tool_calls = self.tool_calls.max(1); self } fn checked_add(self, other: Self) -> Option { Some(Self { tool_calls: self.tool_calls.checked_add(other.tool_calls)?, linden_dollars: self.linden_dollars.checked_add(other.linden_dollars)?, upload_bytes: self.upload_bytes.checked_add(other.upload_bytes)?, inventory_operations: self .inventory_operations .checked_add(other.inventory_operations)?, movement_millimeters: self .movement_millimeters .checked_add(other.movement_millimeters)?, build_prims: self.build_prims.checked_add(other.build_prims)?, }) } fn within(self, maximum: Self) -> bool { self.tool_calls <= maximum.tool_calls && self.linden_dollars <= maximum.linden_dollars && self.upload_bytes <= maximum.upload_bytes && self.inventory_operations <= maximum.inventory_operations && self.movement_millimeters <= maximum.movement_millimeters && self.build_prims <= maximum.build_prims } fn exceeds(self, threshold: Self) -> bool { !self.within(threshold) } } pub trait ResourceEstimator: Send + Sync { fn estimate(&self, arguments: &Value) -> Result; } #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub struct FixedCost(pub ResourceCost); impl ResourceEstimator for FixedCost { fn estimate(&self, _arguments: &Value) -> Result { Ok(self.0) } } #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub enum ApprovalRule { Never, Always, WhenExceeds(ResourceCost), } pub struct PolicyTool { pub definition: ToolDefinition, pub capability: Capability, pub risk: Risk, pub allowed_origins: AllowedOrigins, pub maximum_cost: ResourceCost, pub idempotency: Idempotency, pub approval: ApprovalRule, pub scheduler_allowed: bool, estimator: Arc, } impl fmt::Debug for PolicyTool { fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { formatter .debug_struct("PolicyTool") .field("definition", &self.definition) .field("capability", &self.capability) .field("risk", &self.risk) .field("allowed_origins", &self.allowed_origins) .field("maximum_cost", &self.maximum_cost) .field("idempotency", &self.idempotency) .field("approval", &self.approval) .field("scheduler_allowed", &self.scheduler_allowed) .finish_non_exhaustive() } } impl PolicyTool { #[allow(clippy::too_many_arguments)] pub fn new( definition: ToolDefinition, capability: Capability, risk: Risk, allowed_origins: AllowedOrigins, maximum_cost: ResourceCost, idempotency: Idempotency, approval: ApprovalRule, scheduler_allowed: bool, estimator: Arc, ) -> Result { definition.validate().map_err(PolicyError::Llm)?; let capability_matches_risk = matches!( (capability, risk), (Capability::Informational, Risk::ReadOnly) | ( Capability::PublicLslRequest | Capability::InventoryMutation, Risk::InventoryMutation ) | (Capability::Movement, Risk::Movement) | (Capability::Build, Risk::Build) | (Capability::ObjectMutation, Risk::ObjectMutation) ); let approval_threshold_valid = match approval { ApprovalRule::WhenExceeds(threshold) => threshold.within(maximum_cost), ApprovalRule::Never | ApprovalRule::Always => true, }; if risk.forbidden_in_milestone() || definition.mutating != risk.is_mutating() || !capability_matches_risk || !approval_threshold_valid || maximum_cost.tool_calls == 0 || maximum_cost.linden_dollars != 0 || (capability == Capability::PublicLslRequest && scheduler_allowed) { return Err(PolicyError::InvalidRegistration); } Ok(Self { definition, capability, risk, allowed_origins, maximum_cost, idempotency, approval, scheduler_allowed, estimator, }) } } #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub struct BudgetLimits { pub per_principal: ResourceCost, pub global: ResourceCost, pub window_seconds: u64, } impl Default for BudgetLimits { fn default() -> Self { Self { per_principal: ResourceCost { tool_calls: 32, linden_dollars: 0, upload_bytes: 4 * 1024 * 1024, inventory_operations: 32, movement_millimeters: 100_000, build_prims: 32, }, global: ResourceCost { tool_calls: 256, linden_dollars: 0, upload_bytes: 16 * 1024 * 1024, inventory_operations: 128, movement_millimeters: 500_000, build_prims: 128, }, window_seconds: 60, } } } #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub struct PolicyLimits { pub budgets: BudgetLimits, pub approval_ttl_seconds: u64, pub max_pending_approvals: usize, pub max_scheduler_grants: usize, pub max_scheduler_runs_per_grant: u64, pub max_scheduler_ttl_seconds: u64, } impl Default for PolicyLimits { fn default() -> Self { Self { budgets: BudgetLimits::default(), approval_ttl_seconds: 300, max_pending_approvals: 128, max_scheduler_grants: 128, max_scheduler_runs_per_grant: 1_024, max_scheduler_ttl_seconds: 86_400, } } } impl PolicyLimits { fn validate(self) -> Result { if self.budgets.window_seconds == 0 || self.budgets.window_seconds > 86_400 || self.budgets.per_principal.tool_calls == 0 || self.budgets.global.tool_calls == 0 || self.budgets.per_principal.linden_dollars != 0 || self.budgets.global.linden_dollars != 0 || self.approval_ttl_seconds == 0 || self.approval_ttl_seconds > 86_400 || self.max_pending_approvals == 0 || self.max_pending_approvals > MAX_APPROVALS || self.max_scheduler_grants == 0 || self.max_scheduler_grants > MAX_SCHEDULER_GRANTS || self.max_scheduler_runs_per_grant == 0 || self.max_scheduler_runs_per_grant > 10_000 || self.max_scheduler_ttl_seconds == 0 || self.max_scheduler_ttl_seconds > 7 * 86_400 || !safe_budget(self.budgets.per_principal) || !safe_budget(self.budgets.global) || !self.budgets.per_principal.within(self.budgets.global) { return Err(PolicyError::UnsafeLimits); } Ok(self) } } #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub enum PolicyDisposition { Allowed, Denied, ApprovalRequired, } #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub enum PolicyReasonCode { Allowed, UnknownTool, InvalidArguments, OriginDenied, CapabilityDenied, ForbiddenMilestoneOperation, ToolCostExceeded, PrincipalBudgetExceeded, GlobalBudgetExceeded, ApprovalRequired, ApprovalUnknown, ApprovalNotGranted, ApprovalExpired, ApprovalReplayed, ApprovalMismatch, ApprovalUnexpected, SchedulerGrantUnknown, SchedulerGrantExpired, SchedulerGrantExhausted, SchedulerPrivilegeEscalation, AuditUnavailable, } #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub enum PolicyFinalOutcome { Denied, ApprovalRequired, ApprovalGranted, Authorized, Completed, Rejected, Failed, AmbiguousMutation, } #[derive(Clone, Debug, Eq, PartialEq)] pub struct PolicyAuditRecord { pub recorded_unix_millis: u64, pub authorization_id: Option, pub approval_id: Option, pub origin: OriginClass, pub origin_avatar_id: Option, pub principal: BoundedText, pub session_id: BoundedText, pub correlation_id: BoundedText, pub tool: BoundedText, pub disposition: PolicyDisposition, pub reason: PolicyReasonCode, pub applied_budget: ResourceCost, pub arguments_hash: BoundedText<64>, pub final_outcome: PolicyFinalOutcome, } #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub struct PolicyAuditError; impl fmt::Display for PolicyAuditError { fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { formatter.write_str("policy audit sink unavailable or full") } } impl Error for PolicyAuditError {} pub trait PolicyAuditSink: Send + Sync { fn emit(&self, record: PolicyAuditRecord) -> Result<(), PolicyAuditError>; } #[derive(Debug)] pub struct MemoryPolicyAudit { capacity: usize, records: Mutex>, } impl MemoryPolicyAudit { pub fn new(capacity: usize) -> Result { if capacity == 0 || capacity > MAX_AUDIT_RECORDS { return Err(PolicyError::UnsafeLimits); } Ok(Self { capacity, records: Mutex::new(VecDeque::with_capacity(capacity)), }) } #[must_use] pub fn snapshot(&self) -> Vec { lock(&self.records).iter().cloned().collect() } } impl PolicyAuditSink for MemoryPolicyAudit { fn emit(&self, record: PolicyAuditRecord) -> Result<(), PolicyAuditError> { let mut records = lock(&self.records); if records.len() == self.capacity { return Err(PolicyAuditError); } records.push_back(record); Ok(()) } } #[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)] pub struct ApprovalId(u64); impl ApprovalId { #[must_use] pub const fn from_raw(value: u64) -> Option { if value == 0 { None } else { Some(Self(value)) } } #[must_use] pub const fn get(self) -> u64 { self.0 } } #[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)] pub struct SchedulerGrantId(u64); #[derive(Clone, Copy, Debug, Eq, PartialEq)] enum ApprovalStatus { Pending, Granted, Denied, Consumed, } #[derive(Clone, Debug)] struct ApprovalRecord { id: ApprovalId, principal: PrincipalKey, context: PolicyRequestContext, origin: OriginClass, tool: String, arguments_hash: [u8; 32], cost: ResourceCost, expires_at: u64, status: ApprovalStatus, } #[derive(Clone, Debug)] struct SchedulerGrant { id: SchedulerGrantId, principal: PrincipalKey, tool: String, arguments_hash: [u8; 32], expires_at: u64, remaining_runs: u64, } #[derive(Clone, Debug)] struct PolicyState { next_id: u64, window_started_at: u64, global_used: ResourceCost, principal_used: BTreeMap, approvals: BTreeMap, scheduler_grants: BTreeMap, } impl Default for PolicyState { fn default() -> Self { Self { next_id: 1, window_started_at: 0, global_used: ResourceCost::default(), principal_used: BTreeMap::new(), approvals: BTreeMap::new(), scheduler_grants: BTreeMap::new(), } } } /// Opaque persistence value. A later storage adapter can durably protect and /// restore it without gaining a way to mint an `AuthorizedAction`. #[derive(Clone, Debug)] pub struct PolicySnapshot(PolicyState); #[derive(Clone, Debug, Eq, PartialEq)] pub enum PolicyError { Boundary(crate::types::BoundaryError), Llm(crate::llm::LlmError), UnsafeLimits, InvalidPrincipal, InvalidContext, InvalidRegistration, DuplicateTool, TooManyTools, AuditUnavailable, } impl fmt::Display for PolicyError { fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Self::Boundary(error) => write!(formatter, "policy boundary rejected input: {error}"), Self::Llm(error) => write!(formatter, "policy tool schema rejected: {error}"), Self::UnsafeLimits => formatter.write_str("unsafe policy limits"), Self::InvalidPrincipal => formatter.write_str("invalid authenticated principal"), Self::InvalidContext => formatter.write_str("invalid policy request context"), Self::InvalidRegistration => formatter.write_str("invalid policy tool registration"), Self::DuplicateTool => formatter.write_str("duplicate policy tool registration"), Self::TooManyTools => formatter.write_str("too many policy tool registrations"), Self::AuditUnavailable => formatter.write_str("policy audit emission failed closed"), } } } impl Error for PolicyError {} impl From for PolicyError { fn from(value: crate::types::BoundaryError) -> Self { Self::Boundary(value) } } #[derive(Debug)] pub struct PolicyEvaluation { pub disposition: PolicyDisposition, pub reason: PolicyReasonCode, pub approval_id: Option, authorization: Option, } impl PolicyEvaluation { #[must_use] pub fn into_authorization(self) -> Option { self.authorization } } #[derive(Clone, Debug)] struct ActionReceipt { authorization_id: u64, context: PolicyRequestContext, origin: OriginClass, principal: PrincipalKey, tool: BoundedText, call_id: BoundedText, cost: ResourceCost, arguments_hash: [u8; 32], idempotency: Idempotency, mutating: bool, } /// Single-use exact authorization. Its private fields prevent callers from /// forging a policy decision or swapping arguments after evaluation. /// /// ```compile_fail /// use metacrate_grid_agent::AuthorizedAction; /// let forged = AuthorizedAction { /* private authorization fields */ }; /// ``` #[derive(Debug)] pub struct AuthorizedAction { call: ProposedToolCall, receipt: ActionReceipt, } impl AuthorizedAction { #[must_use] pub const fn call(&self) -> &ProposedToolCall { &self.call } #[must_use] pub const fn authorization_id(&self) -> u64 { self.receipt.authorization_id } #[must_use] pub const fn applied_budget(&self) -> ResourceCost { self.receipt.cost } } pub struct PolicyGateway { authorized_avatars: BTreeSet, tools: BTreeMap, limits: PolicyLimits, audit: Arc, state: Mutex, } impl fmt::Debug for PolicyGateway { fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { formatter .debug_struct("PolicyGateway") .field("authorized_avatar_count", &self.authorized_avatars.len()) .field("tool_count", &self.tools.len()) .field("limits", &self.limits) .finish_non_exhaustive() } } impl PolicyGateway { pub fn new( authorized_avatars: BTreeSet, tools: Vec, limits: PolicyLimits, audit: Arc, ) -> Result { Self::restore( authorized_avatars, tools, limits, audit, PolicySnapshot(PolicyState::default()), ) } pub fn restore( authorized_avatars: BTreeSet, tools: Vec, limits: PolicyLimits, audit: Arc, snapshot: PolicySnapshot, ) -> Result { let limits = limits.validate()?; if authorized_avatars.len() > MAX_AUTHORIZED_AVATARS || authorized_avatars.contains(&UUID::zero()) { return Err(PolicyError::InvalidPrincipal); } if tools.len() > MAX_POLICY_TOOLS { return Err(PolicyError::TooManyTools); } let mut registry = BTreeMap::new(); for tool in tools { if !tool.maximum_cost.within(limits.budgets.per_principal) || !tool.maximum_cost.within(limits.budgets.global) { return Err(PolicyError::InvalidRegistration); } let name = tool.definition.name.as_str().to_owned(); if registry.insert(name, tool).is_some() { return Err(PolicyError::DuplicateTool); } } if snapshot.0.approvals.len() > MAX_APPROVALS || snapshot.0.scheduler_grants.len() > limits.max_scheduler_grants { return Err(PolicyError::UnsafeLimits); } Ok(Self { authorized_avatars, tools: registry, limits, audit, state: Mutex::new(snapshot.0), }) } #[must_use] pub fn snapshot(&self) -> PolicySnapshot { PolicySnapshot(lock(&self.state).clone()) } /// Returns bounded, content-free approval metadata for operator UIs. #[must_use] pub fn pending_approvals(&self, now: u64) -> Vec { lock(&self.state) .approvals .values() .filter(|approval| { approval.status == ApprovalStatus::Pending && approval.expires_at > now }) .map(|approval| PendingApprovalMetadata { id: approval.id, principal: approval.principal.audit_label(), tool: approval.tool.clone(), expires_at: approval.expires_at, cost: approval.cost, }) .collect() } /// Current global budget use for a redacted control-plane projection. #[must_use] pub fn global_budget_usage(&self) -> ResourceCost { lock(&self.state).global_used } #[cfg(test)] pub(crate) fn pending_approval_count(&self) -> usize { lock(&self.state) .approvals .values() .filter(|approval| approval.status == ApprovalStatus::Pending) .count() } #[must_use] pub fn tools_for(&self, context: &PolicyRequestContext, now: u64) -> Vec { self.tools_for_capabilities(context, now, None) } /// Returns only origin-allowed tools whose capability is in `capabilities`. /// An empty set exposes no tools; filtering can never broaden policy access. #[must_use] pub fn tools_for_capability_set( &self, context: &PolicyRequestContext, now: u64, capabilities: &BTreeSet, ) -> Vec { self.tools_for_capabilities(context, now, Some(capabilities)) } fn tools_for_capabilities( &self, context: &PolicyRequestContext, now: u64, capabilities: Option<&BTreeSet>, ) -> Vec { if let OriginKind::InternalScheduler(id) = &context.origin.0 { let state = lock(&self.state); let Some(grant) = state.scheduler_grants.get(id) else { return Vec::new(); }; if grant.expires_at <= now || grant.remaining_runs == 0 || matches!(&grant.principal, PrincipalKey::Avatar(avatar) if !self.authorized_avatars.contains(avatar)) { return Vec::new(); } return self .tools .get(&grant.tool) .filter(|tool| { origin_allows(tool, OriginClass::InternalScheduler) && capabilities.is_none_or(|allowed| allowed.contains(&tool.capability)) }) .map(|tool| vec![tool.definition.clone()]) .unwrap_or_default(); } let Ok(classified) = self.classify(context, now, None, None) else { return Vec::new(); }; self.tools .values() .filter(|tool| { origin_allows(tool, classified.origin) && capabilities.is_none_or(|allowed| allowed.contains(&tool.capability)) }) .map(|tool| tool.definition.clone()) .collect() } #[allow(clippy::too_many_lines)] // Ordered fail-closed checks mirror the policy audit sequence. pub fn evaluate( &self, context: &PolicyRequestContext, call: &ProposedToolCall, arguments: &Value, approval_id: Option, now: u64, ) -> Result { let encoded_arguments = serde_json::from_str::(call.arguments_json.as_str()); let arguments_hash = match &encoded_arguments { Ok(encoded) => hash_arguments(encoded)?, Err(_) => Sha256::digest(call.arguments_json.as_bytes()).into(), }; let classified = match self.classify( context, now, Some(call.name.as_str()), Some(&arguments_hash), ) { Ok(classified) => classified, Err(reason) => { return self.denied( context, call, fallback_principal(context), OriginClass::InternalScheduler, arguments_hash, reason, ); } }; let Some(tool) = self.tools.get(call.name.as_str()) else { return self.denied( context, call, classified.principal, classified.origin, arguments_hash, PolicyReasonCode::UnknownTool, ); }; if encoded_arguments.map_or(true, |encoded| encoded != *arguments) { return self.denied( context, call, classified.principal, classified.origin, arguments_hash, PolicyReasonCode::InvalidArguments, ); } if tool.definition.schema.validate_value(arguments).is_err() { return self.denied( context, call, classified.principal, classified.origin, arguments_hash, PolicyReasonCode::InvalidArguments, ); } if !tool.allowed_origins.contains(classified.origin) { return self.denied( context, call, classified.principal, classified.origin, arguments_hash, PolicyReasonCode::OriginDenied, ); } if !origin_allows(tool, classified.origin) { return self.denied( context, call, classified.principal, classified.origin, arguments_hash, PolicyReasonCode::CapabilityDenied, ); } if tool.risk.forbidden_in_milestone() { return self.denied( context, call, classified.principal, classified.origin, arguments_hash, PolicyReasonCode::ForbiddenMilestoneOperation, ); } let cost = match tool.estimator.estimate(arguments) { Ok(cost) => cost.normalized(), Err(reason) => { return self.denied( context, call, classified.principal, classified.origin, arguments_hash, reason, ); } }; if cost.linden_dollars != 0 || !cost.within(tool.maximum_cost) { return self.denied_with_cost( context, call, classified.principal, classified.origin, arguments_hash, cost, if cost.linden_dollars != 0 { PolicyReasonCode::ForbiddenMilestoneOperation } else { PolicyReasonCode::ToolCostExceeded }, ); } self.authorize( context, call, classified, arguments_hash, cost, tool, approval_id, now, ) } #[allow(clippy::too_many_arguments, clippy::too_many_lines)] // Atomic approval/budget commit. fn authorize( &self, context: &PolicyRequestContext, call: &ProposedToolCall, classified: ClassifiedOrigin, arguments_hash: [u8; 32], cost: ResourceCost, tool: &PolicyTool, approval_id: Option, now: u64, ) -> Result { let requires_approval = match tool.approval { ApprovalRule::Never => false, ApprovalRule::Always => true, ApprovalRule::WhenExceeds(threshold) => cost.exceeds(threshold), }; let mut state = lock(&self.state); rotate_budgets(&mut state, self.limits.budgets, now); let mut approval_to_consume = None; if requires_approval { if let Some(id) = approval_id { let Some(approval) = state.approvals.get(&id) else { drop(state); return self.denied_with_cost( context, call, classified.principal, classified.origin, arguments_hash, cost, PolicyReasonCode::ApprovalUnknown, ); }; let reason = if approval.expires_at <= now { Some(PolicyReasonCode::ApprovalExpired) } else if approval.principal != classified.principal || approval.tool != call.name.as_str() || approval.arguments_hash != arguments_hash || approval.cost != cost { Some(PolicyReasonCode::ApprovalMismatch) } else { match approval.status { ApprovalStatus::Pending => Some(PolicyReasonCode::ApprovalNotGranted), ApprovalStatus::Granted => None, ApprovalStatus::Denied | ApprovalStatus::Consumed => { Some(PolicyReasonCode::ApprovalReplayed) } } }; if let Some(reason) = reason { drop(state); return self.denied_with_cost( context, call, classified.principal, classified.origin, arguments_hash, cost, reason, ); } approval_to_consume = Some(id); } else { if let Some(existing) = state.approvals.values().find(|approval| { approval.principal == classified.principal && approval.tool == call.name.as_str() && approval.arguments_hash == arguments_hash && approval.status == ApprovalStatus::Pending && approval.expires_at > now }) { let id = existing.id; drop(state); return self.approval_required( context, call, classified.principal, classified.origin, arguments_hash, cost, id, ); } let pending = state .approvals .values() .filter(|approval| { approval.status == ApprovalStatus::Pending && approval.expires_at > now }) .count(); if pending >= self.limits.max_pending_approvals { drop(state); return self.denied_with_cost( context, call, classified.principal, classified.origin, arguments_hash, cost, PolicyReasonCode::PrincipalBudgetExceeded, ); } if state.approvals.len() == MAX_APPROVALS { let removable = state.approvals.iter().find_map(|(id, approval)| { (approval.expires_at <= now || matches!( approval.status, ApprovalStatus::Denied | ApprovalStatus::Consumed )) .then_some(*id) }); let Some(removable) = removable else { drop(state); return self.denied_with_cost( context, call, classified.principal, classified.origin, arguments_hash, cost, PolicyReasonCode::GlobalBudgetExceeded, ); }; state.approvals.remove(&removable); } let id = ApprovalId(next_id(&mut state)); let record = ApprovalRecord { id, principal: classified.principal.clone(), context: context.clone(), origin: classified.origin, tool: call.name.as_str().to_owned(), arguments_hash, cost, expires_at: now.saturating_add(self.limits.approval_ttl_seconds), status: ApprovalStatus::Pending, }; let audit = audit_record( context, classified.origin, &classified.principal, call.name.clone(), None, Some(id), PolicyDisposition::ApprovalRequired, PolicyReasonCode::ApprovalRequired, cost, arguments_hash, PolicyFinalOutcome::ApprovalRequired, )?; self.emit(audit)?; state.approvals.insert(id, record); return Ok(PolicyEvaluation { disposition: PolicyDisposition::ApprovalRequired, reason: PolicyReasonCode::ApprovalRequired, approval_id: Some(id), authorization: None, }); } } else if approval_id.is_some() { drop(state); return self.denied_with_cost( context, call, classified.principal, classified.origin, arguments_hash, cost, PolicyReasonCode::ApprovalUnexpected, ); } let principal_used = state .principal_used .get(&classified.principal) .copied() .unwrap_or_default(); let Some(next_principal) = principal_used.checked_add(cost) else { drop(state); return self.denied_with_cost( context, call, classified.principal, classified.origin, arguments_hash, cost, PolicyReasonCode::PrincipalBudgetExceeded, ); }; if !next_principal.within(self.limits.budgets.per_principal) { drop(state); return self.denied_with_cost( context, call, classified.principal, classified.origin, arguments_hash, cost, PolicyReasonCode::PrincipalBudgetExceeded, ); } let Some(next_global) = state.global_used.checked_add(cost) else { drop(state); return self.denied_with_cost( context, call, classified.principal, classified.origin, arguments_hash, cost, PolicyReasonCode::GlobalBudgetExceeded, ); }; if !next_global.within(self.limits.budgets.global) { drop(state); return self.denied_with_cost( context, call, classified.principal, classified.origin, arguments_hash, cost, PolicyReasonCode::GlobalBudgetExceeded, ); } let authorization_id = next_id(&mut state); let record = audit_record( context, classified.origin, &classified.principal, call.name.clone(), Some(authorization_id), approval_to_consume, PolicyDisposition::Allowed, PolicyReasonCode::Allowed, cost, arguments_hash, PolicyFinalOutcome::Authorized, )?; self.emit(record)?; state.global_used = next_global; state .principal_used .insert(classified.principal.clone(), next_principal); if let Some(id) = approval_to_consume && let Some(approval) = state.approvals.get_mut(&id) { approval.status = ApprovalStatus::Consumed; } if let Some(grant_id) = classified.scheduler_grant && let Some(grant) = state.scheduler_grants.get_mut(&grant_id) { grant.remaining_runs = grant.remaining_runs.saturating_sub(1); } let receipt = ActionReceipt { authorization_id, context: context.clone(), origin: classified.origin, principal: classified.principal, tool: call.name.clone(), call_id: call.call_id.clone(), cost, arguments_hash, idempotency: tool.idempotency, mutating: tool.risk.is_mutating(), }; Ok(PolicyEvaluation { disposition: PolicyDisposition::Allowed, reason: PolicyReasonCode::Allowed, approval_id: approval_to_consume, authorization: Some(AuthorizedAction { call: call.clone(), receipt, }), }) } pub fn grant_approval( &self, id: ApprovalId, _operator: &AuthenticatedPrincipal, now: u64, ) -> Result { let mut state = lock(&self.state); let Some(approval) = state.approvals.get_mut(&id) else { return Ok(PolicyReasonCode::ApprovalUnknown); }; if approval.expires_at <= now { return Ok(PolicyReasonCode::ApprovalExpired); } if approval.status != ApprovalStatus::Pending { return Ok(PolicyReasonCode::ApprovalReplayed); } let audit = audit_record( &approval.context, approval.origin, &approval.principal, BoundedText::new("policy.tool", approval.tool.clone())?, None, Some(id), PolicyDisposition::Allowed, PolicyReasonCode::Allowed, approval.cost, approval.arguments_hash, PolicyFinalOutcome::ApprovalGranted, )?; self.emit(audit)?; approval.status = ApprovalStatus::Granted; Ok(PolicyReasonCode::Allowed) } pub fn deny_approval( &self, id: ApprovalId, _operator: &AuthenticatedPrincipal, now: u64, ) -> Result { let mut state = lock(&self.state); let Some(approval) = state.approvals.get_mut(&id) else { return Ok(PolicyReasonCode::ApprovalUnknown); }; if approval.expires_at <= now { return Ok(PolicyReasonCode::ApprovalExpired); } if approval.status != ApprovalStatus::Pending { return Ok(PolicyReasonCode::ApprovalReplayed); } let audit = audit_record( &approval.context, approval.origin, &approval.principal, BoundedText::new("policy.tool", approval.tool.clone())?, None, Some(id), PolicyDisposition::Denied, PolicyReasonCode::ApprovalNotGranted, approval.cost, approval.arguments_hash, PolicyFinalOutcome::Denied, )?; self.emit(audit)?; approval.status = ApprovalStatus::Denied; Ok(PolicyReasonCode::ApprovalNotGranted) } /// Consumes the originating authorization so it cannot be replayed to /// create more than one scheduler grant. #[allow(clippy::needless_pass_by_value)] pub fn issue_scheduler_grant( &self, action: AuthorizedAction, remaining_runs: u64, expires_at: u64, now: u64, ) -> Result { if remaining_runs == 0 || remaining_runs > self.limits.max_scheduler_runs_per_grant || expires_at <= now || expires_at > now.saturating_add(self.limits.max_scheduler_ttl_seconds) || !matches!( action.receipt.origin, OriginClass::AuthorizedIm | OriginClass::LocalOperator ) || !self .tools .get(action.receipt.tool.as_str()) .is_some_and(|tool| tool.scheduler_allowed) { return Err(PolicyReasonCode::SchedulerPrivilegeEscalation); } let mut state = lock(&self.state); if state.scheduler_grants.len() >= self.limits.max_scheduler_grants { return Err(PolicyReasonCode::GlobalBudgetExceeded); } let id = SchedulerGrantId(next_id(&mut state)); state.scheduler_grants.insert( id, SchedulerGrant { id, principal: action.receipt.principal.clone(), tool: action.receipt.tool.as_str().to_owned(), arguments_hash: action.receipt.arguments_hash, expires_at, remaining_runs, }, ); Ok(id) } fn classify( &self, context: &PolicyRequestContext, now: u64, tool: Option<&str>, arguments_hash: Option<&[u8; 32]>, ) -> Result { match &context.origin.0 { OriginKind::PublicChat(id) if *id == UUID::zero() => { Err(PolicyReasonCode::OriginDenied) } OriginKind::PublicChat(id) => Ok(ClassifiedOrigin { origin: OriginClass::PublicChat, principal: PrincipalKey::Avatar(*id), scheduler_grant: None, }), OriginKind::InstantMessage(id) if *id == UUID::zero() => { Err(PolicyReasonCode::OriginDenied) } OriginKind::InstantMessage(id) => Ok(ClassifiedOrigin { origin: if self.authorized_avatars.contains(id) { OriginClass::AuthorizedIm } else { OriginClass::UnprivilegedIm }, principal: PrincipalKey::Avatar(*id), scheduler_grant: None, }), OriginKind::LocalOperator(principal) => Ok(ClassifiedOrigin { origin: OriginClass::LocalOperator, principal: PrincipalKey::Operator(principal.clone()), scheduler_grant: None, }), OriginKind::InternalScheduler(id) => { let state = lock(&self.state); let grant = state .scheduler_grants .get(id) .ok_or(PolicyReasonCode::SchedulerGrantUnknown)?; if grant.id != *id || grant.expires_at <= now { return Err(PolicyReasonCode::SchedulerGrantExpired); } if grant.remaining_runs == 0 { return Err(PolicyReasonCode::SchedulerGrantExhausted); } if grant.remaining_runs > self.limits.max_scheduler_runs_per_grant { return Err(PolicyReasonCode::SchedulerPrivilegeEscalation); } if tool != Some(grant.tool.as_str()) || arguments_hash != Some(&grant.arguments_hash) || matches!(&grant.principal, PrincipalKey::Avatar(avatar) if !self.authorized_avatars.contains(avatar)) { return Err(PolicyReasonCode::SchedulerPrivilegeEscalation); } Ok(ClassifiedOrigin { origin: OriginClass::InternalScheduler, principal: grant.principal.clone(), scheduler_grant: Some(*id), }) } } } #[allow(clippy::needless_pass_by_value)] // Denial branches transfer the classified principal. fn denied( &self, context: &PolicyRequestContext, call: &ProposedToolCall, principal: PrincipalKey, origin: OriginClass, arguments_hash: [u8; 32], reason: PolicyReasonCode, ) -> Result { self.denied_with_cost( context, call, principal, origin, arguments_hash, ResourceCost::default(), reason, ) } #[allow(clippy::needless_pass_by_value, clippy::too_many_arguments)] fn denied_with_cost( &self, context: &PolicyRequestContext, call: &ProposedToolCall, principal: PrincipalKey, origin: OriginClass, arguments_hash: [u8; 32], cost: ResourceCost, reason: PolicyReasonCode, ) -> Result { self.emit(audit_record( context, origin, &principal, call.name.clone(), None, None, PolicyDisposition::Denied, reason, cost, arguments_hash, PolicyFinalOutcome::Denied, )?)?; Ok(PolicyEvaluation { disposition: PolicyDisposition::Denied, reason, approval_id: None, authorization: None, }) } #[allow(clippy::needless_pass_by_value, clippy::too_many_arguments)] fn approval_required( &self, context: &PolicyRequestContext, call: &ProposedToolCall, principal: PrincipalKey, origin: OriginClass, arguments_hash: [u8; 32], cost: ResourceCost, id: ApprovalId, ) -> Result { self.emit(audit_record( context, origin, &principal, call.name.clone(), None, Some(id), PolicyDisposition::ApprovalRequired, PolicyReasonCode::ApprovalRequired, cost, arguments_hash, PolicyFinalOutcome::ApprovalRequired, )?)?; Ok(PolicyEvaluation { disposition: PolicyDisposition::ApprovalRequired, reason: PolicyReasonCode::ApprovalRequired, approval_id: Some(id), authorization: None, }) } fn emit(&self, record: PolicyAuditRecord) -> Result<(), PolicyError> { self.audit .emit(record) .map_err(|_| PolicyError::AuditUnavailable) } fn emit_outcome( &self, receipt: &ActionReceipt, outcome: PolicyFinalOutcome, ) -> Result<(), PolicyError> { self.emit(audit_record( &receipt.context, receipt.origin, &receipt.principal, receipt.tool.clone(), Some(receipt.authorization_id), None, PolicyDisposition::Allowed, PolicyReasonCode::Allowed, receipt.cost, receipt.arguments_hash, outcome, )?) } } #[derive(Clone, Debug)] struct ClassifiedOrigin { origin: OriginClass, principal: PrincipalKey, scheduler_grant: Option, } fn origin_allows(tool: &PolicyTool, origin: OriginClass) -> bool { if !tool.allowed_origins.contains(origin) { return false; } match origin { OriginClass::PublicChat => { (tool.risk == Risk::ReadOnly && tool.capability == Capability::Informational) || tool.capability == Capability::PublicLslRequest } OriginClass::UnprivilegedIm => { tool.risk == Risk::ReadOnly && tool.capability == Capability::Informational } OriginClass::AuthorizedIm | OriginClass::LocalOperator => true, OriginClass::InternalScheduler => tool.scheduler_allowed, } } fn rotate_budgets(state: &mut PolicyState, limits: BudgetLimits, now: u64) { if state.window_started_at == 0 || now >= state .window_started_at .saturating_add(limits.window_seconds) { state.window_started_at = now; state.global_used = ResourceCost::default(); state.principal_used.clear(); } } fn safe_budget(value: ResourceCost) -> bool { value.tool_calls > 0 && value.tool_calls <= MAX_BUDGET_TOOL_CALLS && value.linden_dollars == 0 && value.upload_bytes <= MAX_BUDGET_UPLOAD_BYTES && value.inventory_operations <= MAX_BUDGET_INVENTORY_OPERATIONS && value.movement_millimeters <= MAX_BUDGET_MOVEMENT_MILLIMETERS && value.build_prims <= MAX_BUDGET_BUILD_PRIMS } fn next_id(state: &mut PolicyState) -> u64 { let id = state.next_id; state.next_id = state.next_id.saturating_add(1); id } fn fallback_principal(context: &PolicyRequestContext) -> PrincipalKey { match &context.origin.0 { OriginKind::PublicChat(id) | OriginKind::InstantMessage(id) => PrincipalKey::Avatar(*id), OriginKind::LocalOperator(principal) => PrincipalKey::Operator(principal.clone()), OriginKind::InternalScheduler(_) => PrincipalKey::Operator( AuthenticatedPrincipal::from_authenticated_control("invalid-scheduler") .expect("static principal is valid"), ), } } #[allow(clippy::too_many_arguments)] fn audit_record( context: &PolicyRequestContext, origin: OriginClass, principal: &PrincipalKey, tool: BoundedText, authorization_id: Option, approval_id: Option, disposition: PolicyDisposition, reason: PolicyReasonCode, applied_budget: ResourceCost, arguments_hash: [u8; 32], final_outcome: PolicyFinalOutcome, ) -> Result { Ok(PolicyAuditRecord { recorded_unix_millis: SystemTime::now() .duration_since(UNIX_EPOCH) .map_or(0, |duration| { u64::try_from(duration.as_millis()).unwrap_or(u64::MAX) }), authorization_id, approval_id, origin, origin_avatar_id: principal.avatar_id(), principal: BoundedText::new("policy.audit.principal", principal.audit_label())?, session_id: context.session_id.clone(), correlation_id: context.correlation_id.clone(), tool, disposition, reason, applied_budget, arguments_hash: BoundedText::new("policy.audit.arguments_hash", hex_hash(arguments_hash))?, final_outcome, }) } fn hash_arguments(arguments: &Value) -> Result<[u8; 32], PolicyError> { let canonical = canonical_value(arguments); let bytes = serde_json::to_vec(&canonical).map_err(|_| PolicyError::InvalidRegistration)?; Ok(Sha256::digest(bytes).into()) } fn canonical_value(value: &Value) -> Value { match value { Value::Object(object) => { let sorted = object .iter() .map(|(key, value)| (key.clone(), canonical_value(value))) .collect::>(); Value::Object(sorted.into_iter().collect::>()) } Value::Array(values) => Value::Array(values.iter().map(canonical_value).collect()), _ => value.clone(), } } fn hex_hash(hash: [u8; 32]) -> String { use std::fmt::Write as _; let mut output = String::with_capacity(64); for byte in hash { write!(output, "{byte:02x}").expect("writing to String cannot fail"); } output } fn lock(mutex: &Mutex) -> std::sync::MutexGuard<'_, T> { mutex .lock() .unwrap_or_else(std::sync::PoisonError::into_inner) } fn policy_identifier( field: &'static str, value: impl Into, ) -> Result, PolicyError> { let value = BoundedText::new(field, value)?; if !value.chars().all(|character| { character.is_ascii_alphanumeric() || matches!(character, '.' | '_' | '-' | ':') }) { return Err(PolicyError::InvalidContext); } Ok(value) } #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub enum UntrustedSource { PublicChat, InstantMessage, InventoryMetadata, ObjectText, ParcelData, WebResponse, LlmOutput, GeneratedScript, } /// Bounded untrusted text that can only be rendered as a labelled JSON data /// record. It never contributes system instructions or tool registrations. #[derive(Clone, Debug, Eq, PartialEq)] pub struct UntrustedData { source: UntrustedSource, body: BoundedText, } impl UntrustedData { pub fn new(source: UntrustedSource, body: impl Into) -> Result { Ok(Self { source, body: BoundedText::new("policy.untrusted_data", body)?, }) } pub fn render_json_record(&self) -> Result, PolicyError> { let source = match self.source { UntrustedSource::PublicChat => "public_chat", UntrustedSource::InstantMessage => "instant_message", UntrustedSource::InventoryMetadata => "inventory_metadata", UntrustedSource::ObjectText => "object_text", UntrustedSource::ParcelData => "parcel_data", UntrustedSource::WebResponse => "web_response", UntrustedSource::LlmOutput => "llm_output", UntrustedSource::GeneratedScript => "generated_script", }; let render = |text: &str, truncated: bool| { serde_json::to_string(&serde_json::json!({ "trust":"untrusted_data_only", "source":source, "truncated":truncated, "text":text })) .map_err(|_| PolicyError::InvalidRegistration) }; let complete = render(self.body.as_str(), false)?; if complete.len() <= MAX_MESSAGE_BYTES { return Ok(BoundedText::new("policy.untrusted_record", complete)?); } let boundaries = self .body .char_indices() .map(|(index, _)| index) .chain(std::iter::once(self.body.len())) .collect::>(); let mut low = 0; let mut high = boundaries.len() - 1; while low < high { let middle = low + (high - low).div_ceil(2); if render(&self.body[..boundaries[middle]], true)?.len() <= MAX_MESSAGE_BYTES { low = middle; } else { high = middle - 1; } } let value = render(&self.body[..boundaries[low]], true)?; Ok(BoundedText::new("policy.untrusted_record", value)?) } } /// The only production bridge from the generic tool loop to an action backend. pub struct PolicyToolExecutor { gateway: Arc, backend: Arc, context: PolicyRequestContext, approvals: BTreeMap, now: Arc u64 + Send + Sync>, } impl fmt::Debug for PolicyToolExecutor { fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { formatter .debug_struct("PolicyToolExecutor") .field("gateway", &self.gateway) .field("context", &self.context) .field("approval_count", &self.approvals.len()) .finish_non_exhaustive() } } impl PolicyToolExecutor { pub fn new( gateway: Arc, backend: Arc, context: PolicyRequestContext, approvals: BTreeMap, now: Arc u64 + Send + Sync>, ) -> Result { if approvals.len() > crate::types::MAX_TOOL_CALLS || approvals .keys() .any(|call_id| call_id.is_empty() || call_id.len() > MAX_IDENTIFIER_BYTES) { return Err(PolicyError::UnsafeLimits); } Ok(Self { gateway, backend, context, approvals, now, }) } } impl ToolExecutor for PolicyToolExecutor { fn execute<'a>( &'a self, _definition: &'a ToolDefinition, call: &'a ProposedToolCall, arguments: &'a Value, cancellation: &'a CancellationToken, ) -> ToolFuture<'a> { Box::pin(async move { let approval = self.approvals.get(call.call_id.as_str()).copied(); let Ok(evaluation) = self.gateway .evaluate(&self.context, call, arguments, approval, (self.now)()) else { return fixed_failure("policy gateway failed closed"); }; let Some(action) = evaluation.into_authorization() else { return fixed_rejection("policy denied or requires approval"); }; let receipt = action.receipt.clone(); let result = self.backend.apply(action, cancellation.clone()).await; match result { Ok(ToolCallOutcome::Completed { call_id, result }) if call_id == receipt.call_id => { if self .gateway .emit_outcome(&receipt, PolicyFinalOutcome::Completed) .is_err() { fixed_failure("policy outcome audit failed") } else { ToolExecution::Completed(result) } } Ok(ToolCallOutcome::Rejected { call_id, reason }) if call_id == receipt.call_id => { if self .gateway .emit_outcome(&receipt, PolicyFinalOutcome::Rejected) .is_err() { fixed_failure("policy outcome audit failed") } else { ToolExecution::Rejected( BoundedText::new("policy.backend_rejection", reason.as_str()) .expect("observable detail fits message bound"), ) } } Ok(_) | Err(_) if receipt.mutating && receipt.idempotency == Idempotency::NonIdempotent => { let _ = self .gateway .emit_outcome(&receipt, PolicyFinalOutcome::AmbiguousMutation); ToolExecution::AmbiguousMutation } Ok(_) | Err(_) => { let _ = self .gateway .emit_outcome(&receipt, PolicyFinalOutcome::Failed); fixed_failure("authorized tool backend failed") } } }) } } fn fixed_rejection(message: &'static str) -> ToolExecution { ToolExecution::Rejected( BoundedText::::new("policy.rejection", message) .expect("fixed rejection is bounded"), ) } fn fixed_failure(message: &'static str) -> ToolExecution { ToolExecution::Failed( BoundedText::::new("policy.failure", message) .expect("fixed failure is bounded"), ) }