| Crates.io | lnmp-envelope |
| lib.rs | lnmp-envelope |
| version | 0.5.16 |
| created_at | 2025-11-23 17:32:34.465032+00 |
| updated_at | 2025-12-19 10:04:16.560237+00 |
| description | Operational metadata envelope for LNMP records |
| homepage | https://lnmp.io |
| repository | https://github.com/lnmplang/lnmp-protocol |
| max_upload_size | |
| id | 1946797 |
| size | 95,576 |
Operational metadata envelope for LNMP records, aligned with CloudEvents, Kafka Headers, and W3C Trace Context standards.
FID Registry: All examples use official Field IDs from
registry/fids.yaml.
LNMP Envelope adds operational context (timestamp, source, trace ID, sequence) to LNMP records without affecting deterministic properties or semantic checksums.
SemanticChecksum| Standard | LNMP Envelope Mapping |
|---|---|
| CloudEvents | time → timestamp, source → source, id → trace_id + sequence |
| Kafka Headers | Record-level metadata separate from payload |
| W3C Trace Context | Compatible trace_id format for distributed tracing |
| OpenTelemetry | Seamless span context propagation |
use lnmp_envelope::{EnvelopeBuilder, LnmpRecord, LnmpField, LnmpValue};
// Create a record
let mut record = LnmpRecord::new();
record.add_field(LnmpField { fid: 12, value: LnmpValue::Int(14532) });
// Wrap with envelope
let envelope = EnvelopeBuilder::new(record)
.timestamp(1732373147000)
.source("auth-service")
.trace_id("abc-123-xyz")
.sequence(42)
.build();
assert!(envelope.has_metadata());
Envelope metadata encoded as Type-Length-Value entries:
Type: 0x10 (Timestamp) | Length: 8 | Value: u64 BE
Type: 0x11 (Source) | Length: N | Value: UTF-8 string
Type: 0x12 (TraceID) | Length: M | Value: UTF-8 string
Type: 0x13 (Sequence) | Length: 8 | Value: u64 BE
Example:
use lnmp_envelope::binary_codec::TlvEncoder;
let binary = TlvEncoder::encode(&envelope.metadata).unwrap();
// 51 bytes: 10 00 08 00 00 01 93 59 7c 6d 78 11 00 0c ...
#ENVELOPE timestamp=1732373147000 source=auth-service trace_id="abc-123-xyz" sequence=42
F12=14532
F7=1
POST /api/records HTTP/1.1
X-LNMP-Timestamp: 1732373147000
X-LNMP-Source: auth-service
X-LNMP-Trace-ID: abc-123-xyz
X-LNMP-Sequence: 42
Content-Type: application/lnmp-binary
<binary LNMP record>
ProducerRecord {
headers: [
("lnmp.timestamp", "1732373147000"),
("lnmp.source", "auth-service"),
("lnmp.trace_id", "abc-123-xyz"),
("lnmp.sequence", "42"),
],
value: <binary LNMP record>,
}
metadata {
"lnmp-timestamp": "1732373147000"
"lnmp-source": "auth-service"
"lnmp-trace-id": "abc-123-xyz"
}
use opentelemetry::trace::TraceContextExt;
let span = tracer.start("process_record");
let trace_id = span.span_context().trace_id().to_string();
let envelope = EnvelopeBuilder::new(record)
.trace_id(trace_id)
.build();
fn score_freshness(envelope: &LnmpEnvelope, now: u64) -> f64 {
if let Some(ts) = envelope.metadata.timestamp {
let age_ms = now.saturating_sub(ts);
let age_hours = age_ms as f64 / 3_600_000.0;
(-age_hours / 24.0).exp() // Exponential decay
} else {
0.5 // Unknown age
}
}
let envelope = EnvelopeBuilder::new(record)
.source("tenant:acme")
.label("tenant", "acme")
.label("region", "us-east-1")
.build();
// Route based on source
match envelope.metadata.source.as_deref() {
Some(s) if s.starts_with("tenant:acme") => route_to_acme_cluster(),
_ => route_to_default(),
}
pub struct EnvelopeMetadata {
pub timestamp: Option<u64>, // Unix epoch ms (UTC)
pub source: Option<String>, // Service/device identifier
pub trace_id: Option<String>, // Distributed tracing ID
pub sequence: Option<u64>, // Monotonic sequence number
pub labels: HashMap<String, String>, // Future extensibility
}
pub struct LnmpEnvelope {
pub record: LnmpRecord, // LNMP record (mandatory)
pub metadata: EnvelopeMetadata, // Operational metadata
}
Fluent API for constructing envelopes:
EnvelopeBuilder::new(record)
.timestamp(1732373147000)
.source("my-service")
.trace_id("abc-123")
.sequence(42)
.label("key", "value")
.build()
Critical Invariant:
SemanticChecksum(Record) = f(Record.fields)
Envelope metadata is NOT included in checksum computation.
Verification:
let record = /* ... */;
let cs1 = SemanticChecksum::compute_record(&record);
let envelope = EnvelopeBuilder::new(record.clone())
.timestamp(123456789)
.build();
let cs2 = SemanticChecksum::compute_record(&envelope.record);
assert_eq!(cs1, cs2); // ✅ MUST pass
serde: Enable serde serialization support (optional)See examples/ directory:
envelope_basic_usage.rs - Creating and encoding envelopes (binary TLV)text_format.rs - Text header format demonstrationhttp_binding.rs - HTTP header mapping (X-LNMP-* pattern)kafka_binding.rs - Kafka record headers integrationllm_freshness.rs - LLM freshness scoring with exponential decayRun an example:
cargo run --package lnmp-envelope --example envelope_basic_usage
cargo run --package lnmp-envelope --example llm_freshness
PERFORMANCE.md - Comprehensive performance guide
Formal Specification - Technical specification v1.0
API Documentation - Rust API docs (docs.rs)
Run performance benchmarks:
cargo bench --package lnmp-envelope
Latest Results (Apple M1):
See PERFORMANCE.md for detailed analysis.
Full technical specification: lnmp-envelope-v1.0.md
MIT
Contributions welcome! Please ensure:
cargo test)cargo fmt)cargo clippy)