///|
/// Canonical tool-definition types for the M1 functional Kernel.
///
/// ADR §2.7, §2.8, §2.11: the catalog snapshot is the single source of truth
/// for tool definitions (model-visible) AND for execution owners. The
/// reducer/executor never re-resolves owners from a separate routing cache.
/// Tool execution policy is explicit data — not inferred from the tool name.

///|
/// How a tool may be batched with other tools in the same model completion.
///
/// - `Sequential`: occupies a single-element wave. Safe default; file/shell
///   side effects never race.
/// - `Parallel`: may share a wave with adjacent `Parallel` calls.
/// - `Exclusive`: forms a barrier before and after; never shares a wave.
///
/// `Sequential` is the safe default. Products opt into `Parallel` only for
/// tools whose effects are independently safe, and use `Exclusive` at a
/// visible side-effect boundary.
pub(all) enum ExecutionPolicy {
  Sequential
  Parallel
  Exclusive
} derive(Eq, Debug)

///|
pub impl Show for ExecutionPolicy with fn to_string(self : ExecutionPolicy) -> String {
  match self {
    Sequential => "Sequential"
    Parallel => "Parallel"
    Exclusive => "Exclusive"
  }
}

///|
/// Stable identifier for the provider that owns a tool. The Kernel uses this
/// only for owner lookup in the runtime registry; it does not call into the
/// owner through this type.
pub(all) struct OwnerId {
  value : String
} derive(Eq, Hash, Debug)

///|
pub fn OwnerId::new(value : String) -> Result[OwnerId, String] {
  if value == "" {
    Err("OwnerId must be non-empty")
  } else {
    Ok(OwnerId::{ value, })
  }
}

///|
pub fn OwnerId::unchecked(value : String) -> OwnerId {
  OwnerId::{ value, }
}

///|
pub fn OwnerId::to_string(self : OwnerId) -> String {
  self.value
}

///|
/// A single tool's definition as the model and the executor see it. Owned by
/// the catalog snapshot (T05), not by individual providers.
pub(all) struct ToolDef {
  name : ToolName
  description : String
  input_schema : Json
  owner : OwnerId
  policy : ExecutionPolicy
  /// Optional provenance label (e.g. provider name, MCP server id). Included
  /// in collision diagnostics; never used for routing decisions.
  provenance : String?
} derive(Eq, Debug)

///|
/// Internal builder used by the catalog. Most fields are required; provenance
/// is optional. The catalog builder (T05) validates the schema and policy
/// before constructing this, so by the time a `ToolDef` reaches the
/// reducer, it has already passed composition.
pub fn ToolDef::ToolDef(
  name~ : ToolName,
  description~ : String,
  input_schema~ : Json,
  owner~ : OwnerId,
  policy~ : ExecutionPolicy,
  provenance~ : String?,
) -> ToolDef {
  { name, description, input_schema, owner, policy, provenance }
}

///|
pub impl Show for ToolDef with fn to_string(self : ToolDef) -> String {
  "Tool(\{self.name.to_string()} @ \{self.owner.to_string()}, policy=\{self.policy.to_string()})"
}

///|
/// Result of validating parsed tool arguments against a `ToolDef`'s
/// input schema. The validator (T05) returns this; the reducer (T03) maps
/// `Err` into a `ToolOutcome::NotExecuted(SchemaMismatch)` carrying the
/// original call id.
///
/// The diagnostic deliberately excludes the raw argument payload; it reports
/// only a JSON path and a type expectation, so that prompts and tool arguments
/// never leak into logs.
pub(all) struct SchemaDiagnostic {
  json_path : String
  expected : String
  actual : String
} derive(Eq, Debug)

///|
pub impl Show for SchemaDiagnostic with fn to_string(self : SchemaDiagnostic) -> String {
  "SchemaDiagnostic(path=\{self.json_path}, expected=\{self.expected}, actual=\{self.actual})"
}