{
  "name": "forge-telemetry",
  "language": "rust",
  "version": "0.2.0",
  "description": "ANVIL Telemetry Contract: span collection, audit trails, and observability for the Forge SDK",
  "manifest": "forge-rs/crates/forge-telemetry/Cargo.toml",
  "manifestSha256": "4c226da821ea73d19ca377ab3d5ae90d54b5a43f778cb02809d3c273045b9a78",
  "status": "source-reference",
  "registryPublicationVerified": false,
  "route": "/libraries/rust/forge-telemetry",
  "features": {
    "default": [
      "signed-audit"
    ],
    "signed-audit": [
      "dep:forge-identity"
    ]
  },
  "files": [
    {
      "path": "forge-rs/crates/forge-telemetry/src/audit.rs",
      "sha256": "788707b9b0d54b3cb434626a978d63a8dc54d506171596b3b28bdd717634a87b",
      "artifactSha256": "d5f05e47c441e0f615fdd1a4c90f8174f9f8cf5da87b3b6cf2719832b6b859be",
      "url": "/reference/source/forge-rs/crates/forge-telemetry/src/audit.rs.txt",
      "declarations": [
        {
          "name": "::AuditEntry",
          "line": 41,
          "signature": "#[derive(Debug, Clone, Serialize, Deserialize)]\npub struct AuditEntry {\n/// Sequential index in the trail (0-based).\n\npub index: usize,\n/// The audit event.\n\npub event: AuditEvent\n}",
          "documentation": "A single audit trail entry.\n\nEach entry has a sequential index assigned by the `AuditTrail` and wraps\nan `AuditEvent` with the full event details.\n\n# Examples\n\n```\nuse forge_telemetry::audit::{AuditTrail, AuditEntry};\nuse forge_telemetry::contract::AuditEvent;\nuse forge_core::telemetry::AuditEventKind;\n\nlet mut trail = AuditTrail::new(\"did:oas:l1fe:agent:test\".to_string());\ntrail.append(AuditEvent::new(\n    AuditEventKind::AgentInstantiated,\n    \"did:oas:l1fe:agent:test\".to_string(),\n    serde_json::json!({}),\n));\n\nlet entry = trail.last();\nassert!(entry.is_some());\n```"
        },
        {
          "name": "::AuditTrail",
          "line": 87,
          "signature": "#[derive(Debug, Clone, Serialize, Deserialize)]\npub struct AuditTrail {\n\n}",
          "documentation": "An append-only audit trail with optional Ed25519 signatures.\n\nPer ANVIL Spec section 14.2, every significant agent operation is recorded\nin the audit trail. Entries are timestamped and optionally signed by the\nagent's Ed25519 key. The trail assigns sequential indices starting from 0.\n\n# Invariants\n\n- Entries are append-only; removal is not supported.\n- Each entry's index equals its position in the trail.\n- The agent DID is set at creation and does not change.\n\n# Examples\n\n```\nuse forge_telemetry::audit::AuditTrail;\nuse forge_telemetry::contract::AuditEvent;\nuse forge_core::telemetry::AuditEventKind;\n\nlet mut trail = AuditTrail::new(\"did:oas:l1fe:agent:analyst\".to_string());\nassert!(trail.is_empty());\n\ntrail.append(AuditEvent::new(\n    AuditEventKind::AgentInstantiated,\n    \"did:oas:l1fe:agent:analyst\".to_string(),\n    serde_json::json!({\"module_hash\": \"abc123\"}),\n));\n\ntrail.append(AuditEvent::new(\n    AuditEventKind::ToolInvocation,\n    \"did:oas:l1fe:agent:analyst\".to_string(),\n    serde_json::json!({\"tool\": \"calculator\", \"status\": \"success\"}),\n));\n\nassert_eq!(trail.len(), 2);\nassert_eq!(trail.entries()[0].index, 0);\nassert_eq!(trail.entries()[1].index, 1);\n```"
        },
        {
          "name": "::AuditTrail::new",
          "line": 112,
          "signature": "pub fn new(agent_did: String) -> Self;",
          "documentation": "Creates a new empty `AuditTrail` for the given agent DID.\n\n# Arguments\n\n* `agent_did` - The agent's OAS DID string.\n\n# Returns\n\nAn empty audit trail.\n\n# Examples\n\n```\nuse forge_telemetry::audit::AuditTrail;\n\nlet trail = AuditTrail::new(\"did:oas:l1fe:agent:bot\".to_string());\nassert!(trail.is_empty());\nassert_eq!(trail.agent_did(), \"did:oas:l1fe:agent:bot\");\n```"
        },
        {
          "name": "::AuditTrail::append",
          "line": 143,
          "signature": "pub fn append(&mut self, event: AuditEvent);",
          "documentation": "Appends an audit event to the trail.\n\nThe event is wrapped in an `AuditEntry` with a sequential index\nequal to the current length of the trail.\n\n# Arguments\n\n* `event` - The audit event to append.\n\n# Examples\n\n```\nuse forge_telemetry::audit::AuditTrail;\nuse forge_telemetry::contract::AuditEvent;\nuse forge_core::telemetry::AuditEventKind;\n\nlet mut trail = AuditTrail::new(\"did:oas:l1fe:agent:bot\".to_string());\ntrail.append(AuditEvent::new(\n    AuditEventKind::CapabilityCheck,\n    \"did:oas:l1fe:agent:bot\".to_string(),\n    serde_json::json!({\"capability\": \"web_search\", \"granted\": true}),\n));\nassert_eq!(trail.len(), 1);\n```"
        },
        {
          "name": "::AuditTrail::entries",
          "line": 153,
          "signature": "pub fn entries(&self) -> &[AuditEntry];",
          "documentation": "Returns a slice of all entries in the trail.\n\n# Returns\n\nA slice of `AuditEntry` in sequential order."
        },
        {
          "name": "::AuditTrail::len",
          "line": 158,
          "signature": "pub fn len(&self) -> usize;",
          "documentation": "Returns the number of entries in the trail."
        },
        {
          "name": "::AuditTrail::is_empty",
          "line": 163,
          "signature": "pub fn is_empty(&self) -> bool;",
          "documentation": "Returns `true` if the trail contains no entries."
        },
        {
          "name": "::AuditTrail::last",
          "line": 190,
          "signature": "pub fn last(&self) -> Option<&AuditEntry>;",
          "documentation": "Returns the last entry in the trail, or `None` if empty.\n\n# Returns\n\nA reference to the most recently appended entry.\n\n# Examples\n\n```\nuse forge_telemetry::audit::AuditTrail;\nuse forge_telemetry::contract::AuditEvent;\nuse forge_core::telemetry::AuditEventKind;\n\nlet mut trail = AuditTrail::new(\"did:oas:l1fe:agent:bot\".to_string());\nassert!(trail.last().is_none());\n\ntrail.append(AuditEvent::new(\n    AuditEventKind::AgentInstantiated,\n    \"did:oas:l1fe:agent:bot\".to_string(),\n    serde_json::json!({}),\n));\nassert!(trail.last().is_some());\n```"
        },
        {
          "name": "::AuditTrail::agent_did",
          "line": 195,
          "signature": "pub fn agent_did(&self) -> &str;",
          "documentation": "Returns the agent DID associated with this trail."
        },
        {
          "name": "::AuditTrail::filter_by_kind",
          "line": 240,
          "signature": "pub fn filter_by_kind(&self, kind: &AuditEventKind) -> Vec<&AuditEntry>;",
          "documentation": "Returns all entries matching the given `AuditEventKind`.\n\n# Arguments\n\n* `kind` - The kind of audit event to filter for.\n\n# Returns\n\nA vector of references to entries whose event kind matches.\n\n# Examples\n\n```\nuse forge_telemetry::audit::AuditTrail;\nuse forge_telemetry::contract::AuditEvent;\nuse forge_core::telemetry::AuditEventKind;\n\nlet mut trail = AuditTrail::new(\"did:oas:l1fe:agent:bot\".to_string());\n\ntrail.append(AuditEvent::new(\n    AuditEventKind::ToolInvocation,\n    \"did:oas:l1fe:agent:bot\".to_string(),\n    serde_json::json!({\"tool\": \"search\"}),\n));\ntrail.append(AuditEvent::new(\n    AuditEventKind::NetworkAccess,\n    \"did:oas:l1fe:agent:bot\".to_string(),\n    serde_json::json!({\"url\": \"https://example.com\"}),\n));\ntrail.append(AuditEvent::new(\n    AuditEventKind::ToolInvocation,\n    \"did:oas:l1fe:agent:bot\".to_string(),\n    serde_json::json!({\"tool\": \"calculator\"}),\n));\n\nlet tools = trail.filter_by_kind(&AuditEventKind::ToolInvocation);\nassert_eq!(tools.len(), 2);\n\nlet network = trail.filter_by_kind(&AuditEventKind::NetworkAccess);\nassert_eq!(network.len(), 1);\n```"
        }
      ]
    },
    {
      "path": "forge-rs/crates/forge-telemetry/src/collector.rs",
      "sha256": "fa3e06298d43c2e95e0d099130ee6693aaaea480df6c1be3e9981ab65e6b9273",
      "artifactSha256": "f6e6f002c663639e9247943ca4c530f709bc9ab2f17e2fbe0eb357982633cfa4",
      "url": "/reference/source/forge-rs/crates/forge-telemetry/src/collector.rs.txt",
      "declarations": [
        {
          "name": "::CompletedSpan",
          "line": 39,
          "signature": "#[derive(Debug, Clone, Serialize, Deserialize)]\npub struct CompletedSpan {\n/// The unique identifier for this span.\n\npub span_id: SpanId,\n/// The span name (e.g., `\"anvil.generate\"`, `\"anvil.tool.invoke\"`).\n\npub name: String,\n/// Key-value attributes associated with this span.\n\npub attributes: Vec<(String, String)>,\n/// ISO 8601 timestamp of when the span was started.\n\npub start_time: String,\n/// ISO 8601 timestamp of when the span was ended.\n\npub end_time: String,\n/// The agent's OAS DID, if available.\n\npub agent_did: Option<String>\n}",
          "documentation": "A completed span with timing information.\n\nRepresents a span that has been started and ended, capturing the full\nduration and attributes of the operation.\n\n# Examples\n\n```\nuse forge_telemetry::collector::CompletedSpan;\nuse forge_telemetry::contract::SpanId;\n\nlet span = CompletedSpan {\n    span_id: SpanId::generate(),\n    name: \"anvil.generate\".to_string(),\n    attributes: vec![(\"model\".to_string(), \"gpt-4o\".to_string())],\n    start_time: \"2026-02-19T00:00:00Z\".to_string(),\n    end_time: \"2026-02-19T00:00:01Z\".to_string(),\n    agent_did: Some(\"did:oas:l1fe:agent:test\".to_string()),\n};\nassert_eq!(span.name, \"anvil.generate\");\n```"
        },
        {
          "name": "::SpanCollector",
          "line": 79,
          "signature": "pub trait SpanCollector: Send + Sync {\n    /// Record a completed span.\n    ///\n    /// # Arguments\n    ///\n    /// * `span` - The completed span to record.\n    fn record_span(&self, span: CompletedSpan);\n\n    /// Retrieve all recorded spans.\n    ///\n    /// # Returns\n    ///\n    /// A vector of all completed spans recorded so far.\n    fn spans(&self) -> Vec<CompletedSpan>;\n\n    /// Clear all recorded spans.\n    fn clear(&self);\n\n    /// Number of recorded spans.\n    fn len(&self) -> usize;\n\n    /// Returns `true` if no spans have been recorded.\n    fn is_empty(&self) -> bool;\n}",
          "documentation": "Trait for collecting completed telemetry spans.\n\nImplementations can store spans in memory, write them to disk, or forward\nthem to an external collector.\n\n# Examples\n\n```\nuse forge_telemetry::collector::{SpanCollector, InMemoryCollector, CompletedSpan};\nuse forge_telemetry::contract::SpanId;\n\nlet collector = InMemoryCollector::new();\nassert!(collector.is_empty());\n\ncollector.record_span(CompletedSpan {\n    span_id: SpanId::generate(),\n    name: \"test\".to_string(),\n    attributes: vec![],\n    start_time: \"2026-01-01T00:00:00Z\".to_string(),\n    end_time: \"2026-01-01T00:00:01Z\".to_string(),\n    agent_did: None,\n});\n\nassert_eq!(collector.len(), 1);\n```"
        },
        {
          "name": "::NoopCollector",
          "line": 127,
          "signature": "pub struct NoopCollector;",
          "documentation": "Discards all spans. Zero-cost default for standalone agents.\n\nUse `NoopCollector` when span collection is not needed. All operations\nare no-ops and allocate nothing.\n\n# Examples\n\n```\nuse forge_telemetry::collector::{SpanCollector, NoopCollector, CompletedSpan};\nuse forge_telemetry::contract::SpanId;\n\nlet collector = NoopCollector;\ncollector.record_span(CompletedSpan {\n    span_id: SpanId::generate(),\n    name: \"discarded\".to_string(),\n    attributes: vec![],\n    start_time: \"2026-01-01T00:00:00Z\".to_string(),\n    end_time: \"2026-01-01T00:00:01Z\".to_string(),\n    agent_did: None,\n});\nassert_eq!(collector.len(), 0);\nassert!(collector.is_empty());\n```"
        },
        {
          "name": "::InMemoryCollector",
          "line": 172,
          "signature": "pub struct InMemoryCollector {\n\n}",
          "documentation": "Stores spans in memory. Useful for testing and debugging.\n\nThread-safe via `Mutex`. Not intended for high-throughput production use;\nuse a dedicated exporter for production telemetry.\n\n# Examples\n\n```\nuse forge_telemetry::collector::{SpanCollector, InMemoryCollector, CompletedSpan};\nuse forge_telemetry::contract::SpanId;\n\nlet collector = InMemoryCollector::new();\ncollector.record_span(CompletedSpan {\n    span_id: SpanId::generate(),\n    name: \"test.span\".to_string(),\n    attributes: vec![(\"key\".to_string(), \"value\".to_string())],\n    start_time: \"2026-01-01T00:00:00Z\".to_string(),\n    end_time: \"2026-01-01T00:00:01Z\".to_string(),\n    agent_did: Some(\"did:oas:l1fe:agent:test\".to_string()),\n});\n\nassert_eq!(collector.len(), 1);\nlet spans = collector.spans();\nassert_eq!(spans.len(), 1);\n```"
        },
        {
          "name": "::InMemoryCollector::new",
          "line": 182,
          "signature": "pub fn new() -> Self;",
          "documentation": "Creates a new empty `InMemoryCollector`.\n\n# Returns\n\nAn empty collector ready to record spans."
        },
        {
          "name": "::InMemoryTelemetry",
          "line": 257,
          "signature": "pub struct InMemoryTelemetry {\n\n}",
          "documentation": "In-memory telemetry implementation that stores both spans and events.\n\nWraps `InMemoryCollector` for span storage and tracks active spans to\nproduce `CompletedSpan` records when `end_span` is called. Also collects\nemitted `AuditEvent` entries.\n\nImplements `TelemetryContract` for use in testing and debugging scenarios.\n\n# Examples\n\n```\nuse forge_telemetry::collector::InMemoryTelemetry;\nuse forge_telemetry::contract::{TelemetryContract, AuditEvent};\nuse forge_core::telemetry::AuditEventKind;\n\nlet telemetry = InMemoryTelemetry::new(None);\nlet span_id = telemetry.start_span(\"anvil.generate\", &[(\"model\", \"gpt-4o\")]);\ntelemetry.end_span(&span_id);\n\ntelemetry.emit_event(AuditEvent::new(\n    AuditEventKind::ToolInvocation,\n    \"did:oas:l1fe:agent:test\".to_string(),\n    serde_json::json!({\"tool\": \"web_search\"}),\n));\n\nassert_eq!(telemetry.completed_spans().len(), 1);\nassert_eq!(telemetry.events().len(), 1);\n```"
        },
        {
          "name": "::InMemoryTelemetry::new",
          "line": 274,
          "signature": "pub fn new(agent_did: Option<String>) -> Self;",
          "documentation": "Creates a new `InMemoryTelemetry` instance.\n\n# Arguments\n\n* `agent_did` - Optional agent DID to associate with recorded spans.\n\n# Returns\n\nA new `InMemoryTelemetry` ready to collect spans and events."
        },
        {
          "name": "::InMemoryTelemetry::completed_spans",
          "line": 288,
          "signature": "pub fn completed_spans(&self) -> Vec<CompletedSpan>;",
          "documentation": "Returns all completed spans.\n\n# Returns\n\nA vector of all completed spans that have been started and ended."
        },
        {
          "name": "::InMemoryTelemetry::events",
          "line": 297,
          "signature": "pub fn events(&self) -> Vec<AuditEvent>;",
          "documentation": "Returns all emitted audit events.\n\n# Returns\n\nA vector of all audit events emitted via `emit_event`."
        },
        {
          "name": "::InMemoryTelemetry::clear",
          "line": 302,
          "signature": "pub fn clear(&self);",
          "documentation": "Clears all collected spans and events."
        },
        {
          "name": "::InMemoryTelemetry::span_count",
          "line": 313,
          "signature": "pub fn span_count(&self) -> usize;",
          "documentation": "Returns the number of completed spans."
        },
        {
          "name": "::InMemoryTelemetry::event_count",
          "line": 318,
          "signature": "pub fn event_count(&self) -> usize;",
          "documentation": "Returns the number of emitted events."
        }
      ]
    },
    {
      "path": "forge-rs/crates/forge-telemetry/src/contract.rs",
      "sha256": "ebcc283560f3240f305cce6181c70e3ef0ebf6aedbbf790696f421b113cc5e30",
      "artifactSha256": "2c32c104c15f373c35b172295da9f6be8f447d84763f97a5524e211746d40121",
      "url": "/reference/source/forge-rs/crates/forge-telemetry/src/contract.rs.txt",
      "declarations": [
        {
          "name": "::SpanId",
          "line": 35,
          "signature": "#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]\npub struct SpanId(pub String);",
          "documentation": "A unique span identifier.\n\nEach span started via the `TelemetryContract` receives a `SpanId` that\nmust be passed to `end_span` when the operation completes. IDs are\ngenerated as UUID v4 strings for global uniqueness.\n\n# ANVIL Spec Reference\n\nANVIL Spec section 14.1 -- Telemetry Contract (span identification).\n\n# Examples\n\n```\nuse forge_telemetry::contract::SpanId;\n\nlet id = SpanId::generate();\nassert!(!id.as_str().is_empty());\n```"
        },
        {
          "name": "::SpanId::generate",
          "line": 53,
          "signature": "pub fn generate() -> Self;",
          "documentation": "Creates a new random span ID using UUID v4.\n\n# Returns\n\nA globally unique `SpanId`.\n\n# Examples\n\n```\nuse forge_telemetry::contract::SpanId;\n\nlet a = SpanId::generate();\nlet b = SpanId::generate();\nassert_ne!(a, b);\n```"
        },
        {
          "name": "::SpanId::from_string",
          "line": 71,
          "signature": "pub fn from_string(id: String) -> Self;",
          "documentation": "Creates a `SpanId` from an existing string value.\n\n# Arguments\n\n* `id` - The span identifier string.\n\n# Examples\n\n```\nuse forge_telemetry::contract::SpanId;\n\nlet id = SpanId::from_string(\"custom-span-id\".to_string());\nassert_eq!(id.as_str(), \"custom-span-id\");\n```"
        },
        {
          "name": "::SpanId::as_str",
          "line": 80,
          "signature": "pub fn as_str(&self) -> &str;",
          "documentation": "Returns the span ID as a string slice.\n\n# Returns\n\nThe inner string representation of this span ID."
        },
        {
          "name": "::TelemetryContract",
          "line": 128,
          "signature": "pub trait TelemetryContract: Send + Sync {\n    /// Start a new span with the given name and attributes.\n    ///\n    /// Returns a `SpanId` that must be passed to `end_span` when the\n    /// operation completes.\n    ///\n    /// # Arguments\n    ///\n    /// * `name` - The span name (use dotted notation, e.g., `\"anvil.generate\"`).\n    /// * `attributes` - Key-value pairs of span attributes.\n    ///\n    /// # Returns\n    ///\n    /// A unique `SpanId` for the started span.\n    fn start_span(&self, name: &str, attributes: &[(&str, &str)]) -> SpanId;\n\n    /// End a previously started span.\n    ///\n    /// Marks the span as completed with the current timestamp. If the span\n    /// has already been ended, the behavior is implementation-defined (some\n    /// implementations may silently ignore, others may log a warning).\n    ///\n    /// # Arguments\n    ///\n    /// * `span_id` - The ID returned by `start_span`.\n    fn end_span(&self, span_id: &SpanId);\n\n    /// Emit an audit event for the agent's audit trail.\n    ///\n    /// Events are buffered until `flush` is called, or may be written\n    /// immediately depending on the implementation.\n    ///\n    /// # Arguments\n    ///\n    /// * `event` - The audit event to record.\n    fn emit_event(&self, event: AuditEvent);\n\n    /// Flush any buffered telemetry data to the backend.\n    ///\n    /// # Errors\n    ///\n    /// Returns `TelemetryError::FlushFailed` if the flush operation fails.\n    fn flush(&self) -> Result<(), TelemetryError>;\n}",
          "documentation": "ANVIL Spec section 14.1 -- Telemetry Contract.\n\nDefines the telemetry emission interface for ANVIL-compliant agents.\nImplementations collect spans, emit audit events, and support flushing\nbuffered telemetry data to external systems.\n\n# Contract Guarantees\n\n- `start_span` always returns a valid `SpanId`\n- `end_span` is idempotent for implementations that track span state\n- `emit_event` is non-blocking (events may be buffered)\n- `flush` ensures all buffered data is written to the backend\n\n# Examples\n\n```\nuse forge_telemetry::contract::{TelemetryContract, NoopTelemetry, AuditEvent};\nuse forge_core::telemetry::AuditEventKind;\n\nlet telemetry = NoopTelemetry;\nlet span_id = telemetry.start_span(\"anvil.generate\", &[(\"model\", \"gpt-4o\")]);\ntelemetry.end_span(&span_id);\n\ntelemetry.emit_event(AuditEvent::new(\n    AuditEventKind::AgentInstantiated,\n    \"did:oas:l1fe:agent:bot\".to_string(),\n    serde_json::json!({\"module\": \"test\"}),\n));\n\nassert!(telemetry.flush().is_ok());\n```"
        },
        {
          "name": "::AuditEvent",
          "line": 200,
          "signature": "#[derive(Debug, Clone, Serialize, Deserialize)]\npub struct AuditEvent {\n/// The kind of event.\n\npub kind: AuditEventKind,\n/// The agent's OAS DID.\n\npub agent_did: String,\n/// ISO 8601 timestamp of when the event occurred.\n\npub timestamp: String,\n/// Event-specific details as a JSON value.\n\npub details: serde_json::Value,\n/// Ed25519 signature (hex-encoded), if signed.\n\npub signature: Option<String>\n}",
          "documentation": "An audit event recording a significant agent operation.\n\nEach event is associated with an agent DID, timestamped, and optionally\nsigned by the agent's Ed25519 key. Audit events form the foundation of\nthe agent's audit trail.\n\n# ANVIL Spec Reference\n\nANVIL Spec section 14.3 -- Audit Events.\n\n# Examples\n\n```\nuse forge_telemetry::contract::AuditEvent;\nuse forge_core::telemetry::AuditEventKind;\n\nlet event = AuditEvent::new(\n    AuditEventKind::ToolInvocation,\n    \"did:oas:l1fe:agent:analyzer\".to_string(),\n    serde_json::json!({\"tool\": \"web_search\", \"status\": \"success\"}),\n);\n\nassert_eq!(event.kind, AuditEventKind::ToolInvocation);\nassert_eq!(event.agent_did, \"did:oas:l1fe:agent:analyzer\");\nassert!(event.signature.is_none());\n```"
        },
        {
          "name": "::AuditEvent::new",
          "line": 244,
          "signature": "pub fn new(kind: AuditEventKind, agent_did: String, details: serde_json::Value) -> Self;",
          "documentation": "Creates a new `AuditEvent` with the current UTC timestamp.\n\nThe signature is initially `None`. Call `sign` to attach an Ed25519\nsignature after construction.\n\n# Arguments\n\n* `kind` - The kind of audit event.\n* `agent_did` - The agent's OAS DID string.\n* `details` - Event-specific details as a JSON value.\n\n# Returns\n\nA new `AuditEvent` with the timestamp set to the current UTC time.\n\n# Examples\n\n```\nuse forge_telemetry::contract::AuditEvent;\nuse forge_core::telemetry::AuditEventKind;\n\nlet event = AuditEvent::new(\n    AuditEventKind::LifecycleTransition,\n    \"did:oas:l1fe:agent:bot\".to_string(),\n    serde_json::json!({\"from\": \"created\", \"to\": \"initializing\"}),\n);\n\nassert!(!event.timestamp.is_empty());\nassert!(event.signature.is_none());\n```"
        },
        {
          "name": "::AuditEvent::with_signature",
          "line": 263,
          "signature": "pub fn with_signature(mut self, signature: String) -> Self;",
          "documentation": "Attaches an Ed25519 signature to this event.\n\n# Arguments\n\n* `signature` - The hex-encoded Ed25519 signature.\n\n# Returns\n\nThe event with the signature attached (builder pattern)."
        },
        {
          "name": "::NoopTelemetry",
          "line": 288,
          "signature": "pub struct NoopTelemetry;",
          "documentation": "No-op telemetry implementation that discards all telemetry data.\n\nUsed as the default for agents that do not need telemetry collection\nor when telemetry is disabled. All operations are zero-cost.\n\n# ANVIL Spec Reference\n\nANVIL Spec section 14.1 -- Telemetry Contract (default implementation).\n\n# Examples\n\n```\nuse forge_telemetry::contract::{TelemetryContract, NoopTelemetry};\n\nlet noop = NoopTelemetry;\nlet span = noop.start_span(\"test\", &[]);\nnoop.end_span(&span);\nassert!(noop.flush().is_ok());\n```"
        }
      ]
    },
    {
      "path": "forge-rs/crates/forge-telemetry/src/error.rs",
      "sha256": "47cca4c817edbb919b51893fbdc6152cdb3c4091d9cf4aac95b6cc5d93428fc0",
      "artifactSha256": "93bc84d321f4ac68ecdc3ac8905e4276ba07e8334e3193e19b5bc9afb4cc9e10",
      "url": "/reference/source/forge-rs/crates/forge-telemetry/src/error.rs.txt",
      "declarations": [
        {
          "name": "::TelemetryError",
          "line": 28,
          "signature": "#[derive(Debug, Error)]\npub enum TelemetryError {\n    /// A span with the given ID was not found in the collector.\n    #[error(\"span '{span_id}' not found in telemetry collector\")]\n    SpanNotFound {\n        /// The span ID that was not found.\n        span_id: String,\n    },\n\n    /// An attempt was made to close a span that is already closed.\n    #[error(\"span '{span_id}' has already been closed and cannot be ended again\")]\n    SpanAlreadyClosed {\n        /// The span ID that was already closed.\n        span_id: String,\n    },\n\n    /// An audit entry failed validation.\n    #[error(\"audit entry is invalid: {reason}\")]\n    AuditEntryInvalid {\n        /// The reason the entry is invalid.\n        reason: String,\n    },\n\n    /// The audit trail integrity check failed at the given index.\n    #[error(\"audit trail corrupted at index {index}: {reason}\")]\n    AuditTrailCorrupted {\n        /// The index where corruption was detected.\n        index: usize,\n        /// The reason for the corruption.\n        reason: String,\n    },\n\n    /// Flushing buffered telemetry data to the backend failed.\n    #[error(\"failed to flush telemetry data: {reason}\")]\n    FlushFailed {\n        /// The reason the flush failed.\n        reason: String,\n    },\n\n    /// The span collector has reached its capacity limit.\n    #[error(\"telemetry collector is full (capacity: {capacity} spans)\")]\n    CollectorFull {\n        /// The maximum number of spans the collector can hold.\n        capacity: usize,\n    },\n\n    /// Exporting telemetry data to an external system failed.\n    #[error(\"failed to export telemetry data: {reason}\")]\n    ExportFailed {\n        /// The reason the export failed.\n        reason: String,\n    },\n\n    /// An audit trail signature or hash chain verification failed.\n    ///\n    /// This indicates either a tampered entry, a wrong signer, or a\n    /// corrupted hash chain in the signed audit trail.\n    ///\n    /// # ANVIL Spec \u00a714.2\n    #[error(\"audit trail verification failed: {reason}\")]\n    AuditVerificationFailed {\n        /// Human-readable description of the verification failure.\n        reason: String,\n    },\n}",
          "documentation": "Errors that can occur during telemetry operations.\n\nEach variant provides specific context about the failure, including\nidentifiers and reasons to enable actionable debugging.\n\n# Examples\n\n```\nuse forge_telemetry::error::TelemetryError;\n\nlet err = TelemetryError::SpanNotFound {\n    span_id: \"abc-123\".to_string(),\n};\nassert!(err.to_string().contains(\"abc-123\"));\n```"
        }
      ]
    },
    {
      "path": "forge-rs/crates/forge-telemetry/src/lib.rs",
      "sha256": "037357b9d7c56e9fcae4946462abe6ee725b9edf247b0adb9e6a3b629f81e75a",
      "artifactSha256": "31f0fdc2ab5ec71f6f2ed52f1e01162061ce05980fea15de0d76bd4085cca2e9",
      "url": "/reference/source/forge-rs/crates/forge-telemetry/src/lib.rs.txt",
      "declarations": [
        {
          "name": "audit",
          "line": 93,
          "signature": "pub mod audit;",
          "documentation": "# forge-telemetry\n\nANVIL Telemetry Contract: span collection, audit trails, and observability\nfor the Forge SDK.\n\nThis crate defines the telemetry emission interface for ANVIL-compliant agents.\nIt provides:\n\n- **`TelemetryContract` trait** \u2014 The standard interface for starting/ending spans,\n  emitting audit events, and flushing buffered data (ANVIL Spec section 14.1)\n- **Span collection** \u2014 `SpanCollector` trait with `NoopCollector` and\n  `InMemoryCollector` implementations\n- **Audit trail** \u2014 Append-only `AuditTrail` with sequential indexing and\n  filtering by event kind (ANVIL Spec section 14.2)\n- **`NoopTelemetry`** \u2014 Zero-cost default for agents that do not need telemetry\n- **`InMemoryTelemetry`** \u2014 Full in-memory implementation for testing and debugging\n- **Typed errors** \u2014 `TelemetryError` with actionable messages\n\n# Architecture\n\n`forge-telemetry` depends on `forge-core` for span constants (`SPAN_GENERATE`, etc.)\nand base types (`AuditEventKind`, `ForgeSpan`, `ForgeEvent`). It does NOT depend on\n`forge-agent` \u2014 agent crates depend on this crate, not the other way around.\n\n# ANVIL Spec Reference\n\n- Section 14.1 \u2014 Telemetry Contract\n- Section 14.2 \u2014 Audit Trail\n- Section 14.3 \u2014 Audit Events\n\n# Examples\n\n## Using `NoopTelemetry` (zero-cost default)\n\n```\nuse forge_telemetry::contract::{TelemetryContract, NoopTelemetry};\n\nlet telemetry = NoopTelemetry;\nlet span = telemetry.start_span(\"anvil.generate\", &[(\"model\", \"gpt-4o\")]);\ntelemetry.end_span(&span);\nassert!(telemetry.flush().is_ok());\n```\n\n## Using `InMemoryTelemetry` for testing\n\n```\nuse forge_telemetry::collector::InMemoryTelemetry;\nuse forge_telemetry::contract::{TelemetryContract, AuditEvent};\nuse forge_core::telemetry::AuditEventKind;\n\nlet telemetry = InMemoryTelemetry::new(Some(\"did:oas:l1fe:agent:test\".to_string()));\n\nlet span_id = telemetry.start_span(\"anvil.tool.invoke\", &[(\"tool\", \"search\")]);\ntelemetry.end_span(&span_id);\n\ntelemetry.emit_event(AuditEvent::new(\n    AuditEventKind::ToolInvocation,\n    \"did:oas:l1fe:agent:test\".to_string(),\n    serde_json::json!({\"tool\": \"search\", \"status\": \"success\"}),\n));\n\nassert_eq!(telemetry.completed_spans().len(), 1);\nassert_eq!(telemetry.events().len(), 1);\n```\n\n## Building an audit trail\n\n```\nuse forge_telemetry::audit::AuditTrail;\nuse forge_telemetry::contract::AuditEvent;\nuse forge_core::telemetry::AuditEventKind;\n\nlet mut trail = AuditTrail::new(\"did:oas:l1fe:agent:analyst\".to_string());\n\ntrail.append(AuditEvent::new(\n    AuditEventKind::AgentInstantiated,\n    \"did:oas:l1fe:agent:analyst\".to_string(),\n    serde_json::json!({\"module_hash\": \"sha256:abc123\"}),\n));\n\ntrail.append(AuditEvent::new(\n    AuditEventKind::ToolInvocation,\n    \"did:oas:l1fe:agent:analyst\".to_string(),\n    serde_json::json!({\"tool\": \"web_search\"}),\n));\n\nassert_eq!(trail.len(), 2);\nlet tools = trail.filter_by_kind(&AuditEventKind::ToolInvocation);\nassert_eq!(tools.len(), 1);\n```"
        },
        {
          "name": "collector",
          "line": 94,
          "signature": "pub mod collector;",
          "documentation": ""
        },
        {
          "name": "contract",
          "line": 95,
          "signature": "pub mod contract;",
          "documentation": ""
        },
        {
          "name": "error",
          "line": 96,
          "signature": "pub mod error;",
          "documentation": ""
        },
        {
          "name": "signed_audit",
          "line": 97,
          "signature": "pub mod signed_audit;",
          "documentation": ""
        },
        {
          "name": "prelude",
          "line": 100,
          "signature": "pub mod prelude;",
          "documentation": "Re-exports of the most commonly used types."
        },
        {
          "name": "pub use crate::audit::{AuditEntry, AuditTrail};",
          "line": 101,
          "signature": "pub use crate::audit::{AuditEntry, AuditTrail};",
          "documentation": ""
        },
        {
          "name": "pub use crate::collector::{\n        CompletedSpan, InMemoryCollector, InMemoryTelemetry, NoopCollector, SpanCollector,\n    };",
          "line": 102,
          "signature": "pub use crate::collector::{\n        CompletedSpan, InMemoryCollector, InMemoryTelemetry, NoopCollector, SpanCollector,\n    };",
          "documentation": ""
        },
        {
          "name": "pub use crate::contract::{AuditEvent, NoopTelemetry, SpanId, TelemetryContract};",
          "line": 105,
          "signature": "pub use crate::contract::{AuditEvent, NoopTelemetry, SpanId, TelemetryContract};",
          "documentation": ""
        },
        {
          "name": "pub use crate::error::TelemetryError;",
          "line": 106,
          "signature": "pub use crate::error::TelemetryError;",
          "documentation": ""
        },
        {
          "name": "pub use crate::signed_audit::{SignedAuditEntry, SignedAuditTrail};",
          "line": 107,
          "signature": "pub use crate::signed_audit::{SignedAuditEntry, SignedAuditTrail};",
          "documentation": ""
        }
      ]
    },
    {
      "path": "forge-rs/crates/forge-telemetry/src/signed_audit.rs",
      "sha256": "a74610b828086f877775ae88a89222853849ef73960016fcada3f6a56a835ea9",
      "artifactSha256": "7ecee972aba3654875fab0e75d8a885bde42c69d0208b2fde1e53e5d08d14180",
      "url": "/reference/source/forge-rs/crates/forge-telemetry/src/signed_audit.rs.txt",
      "declarations": [
        {
          "name": "::SignedAuditEntry",
          "line": 101,
          "signature": "#[derive(Debug, Clone, Serialize, Deserialize)]\npub struct SignedAuditEntry {\n/// Sequential index in the trail (0-based).\n\npub index: usize,\n/// The audit event data.\n\npub event: AuditEvent,\n/// BLAKE3 hash of the previous entry (or genesis hash for index 0).\n\npub previous_hash: String,\n/// Hex-encoded 64-byte Ed25519 signature over the canonical content.\n\npub signature_hex: String,\n/// BLAKE3 hash of this entry's signed content (used as `previous_hash` by the next entry).\n\npub entry_hash: String\n}",
          "documentation": "A signed audit trail entry with hash chaining.\n\nEach entry extends [`AuditEvent`] with:\n- A sequential `index` (0-based)\n- A `previous_hash` linking to the prior entry (BLAKE3)\n- A 64-byte Ed25519 `signature` over the canonical content\n- The `entry_hash` (BLAKE3 of the signed content, used as `previous_hash` by the next entry)\n\n# ANVIL Spec \u00a714.2\n\n# Examples\n\n```\nuse forge_telemetry::signed_audit::{SignedAuditTrail, SignedAuditEntry};\nuse forge_telemetry::contract::AuditEvent;\nuse forge_core::telemetry::AuditEventKind;\nuse forge_identity::lineage::create_hmr_identity;\n\nlet hmr = create_hmr_identity(\"test\", \"entry-demo\").unwrap();\nlet mut trail = SignedAuditTrail::new(&hmr);\n\ntrail.append_signed(\n    AuditEvent::new(\n        AuditEventKind::ToolInvocation,\n        \"did:oas:test:hmr:entry-demo\".to_string(),\n        serde_json::json!({\"tool\": \"search\"}),\n    ),\n    &hmr,\n);\n\nlet entry = trail.entries().first().unwrap();\nassert_eq!(entry.index, 0);\nassert!(!entry.signature_hex.is_empty());\nassert!(!entry.entry_hash.is_empty());\n```"
        },
        {
          "name": "::SignedAuditTrail",
          "line": 225,
          "signature": "#[derive(Debug, Clone, Serialize, Deserialize)]\npub struct SignedAuditTrail {\n\n}",
          "documentation": "An Ed25519-signed, hash-chained, append-only audit trail.\n\nEvery entry appended to this trail is:\n1. Signed with the agent's Ed25519 key\n2. Hash-chained to the previous entry via BLAKE3\n\nThe trail stores the agent's public key bytes (NOT the private key) for\nverification purposes. The private key is only used during `append()`.\n\n# Security\n\n- The private key is borrowed during `append()` and never stored.\n- The public key is stored for verification.\n- Entries are append-only.\n- The hash chain enables tamper detection.\n\n# ANVIL Spec \u00a714.2\n\n# Examples\n\n```\nuse forge_telemetry::signed_audit::SignedAuditTrail;\nuse forge_telemetry::contract::AuditEvent;\nuse forge_core::telemetry::AuditEventKind;\nuse forge_identity::lineage::create_hmr_identity;\n\nlet hmr = create_hmr_identity(\"test\", \"trail-demo\").unwrap();\nlet mut trail = SignedAuditTrail::new(&hmr);\n\ntrail.append_signed(\n    AuditEvent::new(\n        AuditEventKind::AgentInstantiated,\n        hmr.did().to_string(),\n        serde_json::json!({}),\n    ),\n    &hmr,\n);\n\nassert_eq!(trail.len(), 1);\nassert!(trail.verify_all().is_ok());\n```"
        },
        {
          "name": "::SignedAuditTrail::new",
          "line": 261,
          "signature": "#[cfg(feature = \"signed-audit\")]\npub fn new(identity: &forge_identity::agent_identity::ForgeAgentIdentity) -> Self;",
          "documentation": "Creates a new empty `SignedAuditTrail` bound to the given agent identity.\n\nThe agent's DID and public key are extracted from the identity. The\nprivate key is NOT stored; it is only borrowed during [`append_signed`](Self::append_signed).\n\n# Arguments\n\n* `identity` - The agent's [`ForgeAgentIdentity`](forge_identity::agent_identity::ForgeAgentIdentity).\n\n# Returns\n\nAn empty signed audit trail.\n\n# Examples\n\n```\nuse forge_telemetry::signed_audit::SignedAuditTrail;\nuse forge_identity::lineage::create_hmr_identity;\n\nlet hmr = create_hmr_identity(\"test\", \"new-demo\").unwrap();\nlet trail = SignedAuditTrail::new(&hmr);\nassert!(trail.is_empty());\nassert_eq!(trail.agent_did(), hmr.did());\n```"
        },
        {
          "name": "::SignedAuditTrail::from_parts",
          "line": 279,
          "signature": "pub fn from_parts(agent_did: String, verifying_key_hex: String) -> Self;",
          "documentation": "Creates a `SignedAuditTrail` from raw components (for deserialization/testing).\n\n# Arguments\n\n* `agent_did` - The agent's DID.\n* `verifying_key_hex` - Hex-encoded 32-byte Ed25519 public key.\n\n# Returns\n\nAn empty signed audit trail."
        },
        {
          "name": "::SignedAuditTrail::append_signed",
          "line": 299,
          "signature": "#[cfg(feature = \"signed-audit\")]\npub fn append_signed(\n        &mut self,\n        event: AuditEvent,\n        identity: &forge_identity::agent_identity::ForgeAgentIdentity,\n    );",
          "documentation": "Appends a signed audit event using the provided identity for signing.\n\nThis is the primary append method. It borrows the identity only for\nthe duration of the signing operation.\n\n# Arguments\n\n* `event` - The audit event to append.\n* `identity` - The agent identity providing the signing key.\n\n# ANVIL Spec \u00a714.2"
        },
        {
          "name": "::SignedAuditTrail::verify_entry",
          "line": 387,
          "signature": "pub fn verify_entry(&self, index: usize) -> Result<(), TelemetryError>;",
          "documentation": "Verifies a single audit entry's signature against the stored public key.\n\n# Arguments\n\n* `index` - The index of the entry to verify.\n\n# Returns\n\n`Ok(())` if the signature is valid.\n\n# Errors\n\nReturns [`TelemetryError::AuditVerificationFailed`] if:\n- The index is out of bounds.\n- The signature does not verify.\n- The public key bytes are malformed.\n\n# Examples\n\n```\nuse forge_telemetry::signed_audit::SignedAuditTrail;\nuse forge_telemetry::contract::AuditEvent;\nuse forge_core::telemetry::AuditEventKind;\nuse forge_identity::lineage::create_hmr_identity;\n\nlet hmr = create_hmr_identity(\"test\", \"verify-demo\").unwrap();\nlet mut trail = SignedAuditTrail::new(&hmr);\ntrail.append_signed(\n    AuditEvent::new(\n        AuditEventKind::AgentInstantiated,\n        hmr.did().to_string(),\n        serde_json::json!({}),\n    ),\n    &hmr,\n);\nassert!(trail.verify_entry(0).is_ok());\n```"
        },
        {
          "name": "::SignedAuditTrail::verify_all",
          "line": 534,
          "signature": "pub fn verify_all(&self) -> Result<(), TelemetryError>;",
          "documentation": "Verifies all entries in the trail: signatures and hash chain integrity.\n\nWalks the entire trail from index 0 to the end, verifying each entry's\nEd25519 signature and hash chain link.\n\n# Returns\n\n`Ok(())` if all entries verify successfully.\n\n# Errors\n\nReturns [`TelemetryError::AuditVerificationFailed`] at the first\nentry that fails verification, with details about the failure.\n\n# Examples\n\n```\nuse forge_telemetry::signed_audit::SignedAuditTrail;\nuse forge_telemetry::contract::AuditEvent;\nuse forge_core::telemetry::AuditEventKind;\nuse forge_identity::lineage::create_hmr_identity;\n\nlet hmr = create_hmr_identity(\"test\", \"verify-all-demo\").unwrap();\nlet mut trail = SignedAuditTrail::new(&hmr);\n\ntrail.append_signed(\n    AuditEvent::new(\n        AuditEventKind::AgentInstantiated,\n        hmr.did().to_string(),\n        serde_json::json!({}),\n    ),\n    &hmr,\n);\ntrail.append_signed(\n    AuditEvent::new(\n        AuditEventKind::ToolInvocation,\n        hmr.did().to_string(),\n        serde_json::json!({\"tool\": \"search\"}),\n    ),\n    &hmr,\n);\n\nassert!(trail.verify_all().is_ok());\n```"
        },
        {
          "name": "::SignedAuditTrail::entries",
          "line": 542,
          "signature": "pub fn entries(&self) -> &[SignedAuditEntry];",
          "documentation": "Returns a slice of all signed entries in the trail."
        },
        {
          "name": "::SignedAuditTrail::len",
          "line": 547,
          "signature": "pub fn len(&self) -> usize;",
          "documentation": "Returns the number of entries in the trail."
        },
        {
          "name": "::SignedAuditTrail::is_empty",
          "line": 552,
          "signature": "pub fn is_empty(&self) -> bool;",
          "documentation": "Returns `true` if the trail contains no entries."
        },
        {
          "name": "::SignedAuditTrail::last",
          "line": 557,
          "signature": "pub fn last(&self) -> Option<&SignedAuditEntry>;",
          "documentation": "Returns the last entry in the trail, or `None` if empty."
        },
        {
          "name": "::SignedAuditTrail::agent_did",
          "line": 562,
          "signature": "pub fn agent_did(&self) -> &str;",
          "documentation": "Returns the agent DID associated with this trail."
        },
        {
          "name": "::SignedAuditTrail::verifying_key_hex",
          "line": 567,
          "signature": "pub fn verifying_key_hex(&self) -> &str;",
          "documentation": "Returns the hex-encoded verifying (public) key."
        },
        {
          "name": "::SignedAuditTrail::filter_by_kind",
          "line": 580,
          "signature": "pub fn filter_by_kind(&self, kind: &AuditEventKind) -> Vec<&SignedAuditEntry>;",
          "documentation": "Returns all entries matching the given `AuditEventKind`.\n\n# Arguments\n\n* `kind` - The kind of audit event to filter for.\n\n# Returns\n\nA vector of references to entries whose event kind matches."
        }
      ]
    }
  ]
}
