Joule Code is the coding cargo class of the substrate: a coding operation — an edit, refactor, or generated function — is a content-addressed, signed transition over a source tree, resolved through the energy-tiered cascade (L0 Cache → L1 Lawful → L2 Embed → L3 Model → L4 Wire, stop-at-first-close) with a signed JWP receipt (measured + estimated µJ, honest Provenance) per operation. The agent schema is JouleClaw; L4 frontier agents are reached over ACP with the credential held by the vendor's own client — no protocol token, no required contact with any single company. Stands up the standard to the family schema: - README, SPEC.md (RFC-2119 normative), dual licence (Apache-2.0 code / CC-BY-4.0 spec), ROADMAP, CONTRIBUTING, CHANGELOG. - spec/: cargo (the coding-operation type), cascade (the tier binding), receipt (the JWP energy record), collab (federated, interface-level/Research). - vocab/LEXICON.md. - conformance/v1/: C1 content-addressing, C2 signing, C3 receipt, C4 cascade vectors + VERSIONS + regeneration; real Ed25519 RFC-8032 KATs, derived fields regenerated against the reference library. - joule-code-rs/: lean reference library (schema, cargo, receipt, cascade, conformance). cargo test --workspace passes; the conformance harness runs 11 pass / 0 fail / 7 skip (derived fields pending regeneration). Single-endpoint operation is the v0.1 surface; federated collaboration is specified at interface level and classified Research. Registers the standard in the family README. Co-Authored-By: Claude Opus 4.8 <[email protected]>
113 lines
3.5 KiB
Rust
113 lines
3.5 KiB
Rust
//! Joule Code schema: content addressing, canonical serialization, shared types.
|
|
//!
|
|
//! Implements SPEC §3 (identity / content addressing) and §4 (canonical
|
|
//! serialization), plus the shared [`Tier`] type used across the cargo,
|
|
//! receipt, and cascade crates.
|
|
|
|
use base64::Engine as _;
|
|
use serde::{Deserialize, Serialize};
|
|
|
|
/// Errors from canonical encoding / addressing.
|
|
#[derive(Debug, thiserror::Error)]
|
|
pub enum SchemaError {
|
|
/// Canonical CBOR encoding failed.
|
|
#[error("canonical encoding failed: {0}")]
|
|
Encode(String),
|
|
}
|
|
|
|
/// A content address: `BLAKE3-256` of a canonical serialization, rendered as
|
|
/// `"b3:" + unpadded base64url` (SPEC §3).
|
|
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
|
pub struct ContentId(pub String);
|
|
|
|
impl ContentId {
|
|
/// The address of raw canonical bytes.
|
|
pub fn of_bytes(canonical: &[u8]) -> Self {
|
|
let hash = blake3::hash(canonical);
|
|
let b64 = base64::engine::general_purpose::URL_SAFE_NO_PAD.encode(hash.as_bytes());
|
|
ContentId(format!("b3:{b64}"))
|
|
}
|
|
|
|
/// The address of any value via its canonical CBOR form (SPEC §4).
|
|
pub fn of_canonical<T: Serialize>(value: &T) -> Result<Self, SchemaError> {
|
|
Ok(Self::of_bytes(&canonical_cbor(value)?))
|
|
}
|
|
|
|
/// The textual form, e.g. `"b3:AAAA..."`.
|
|
pub fn as_str(&self) -> &str {
|
|
&self.0
|
|
}
|
|
}
|
|
|
|
impl std::fmt::Display for ContentId {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
f.write_str(&self.0)
|
|
}
|
|
}
|
|
|
|
/// Canonical serialization (SPEC §4): deterministic CBOR. Our load-bearing
|
|
/// types are structs with a fixed field order and contain no floats and no
|
|
/// hash-randomized maps, so `ciborium`'s encoding is deterministic across
|
|
/// platforms for equal values.
|
|
pub fn canonical_cbor<T: Serialize>(value: &T) -> Result<Vec<u8>, SchemaError> {
|
|
let mut buf = Vec::new();
|
|
ciborium::ser::into_writer(value, &mut buf).map_err(|e| SchemaError::Encode(e.to_string()))?;
|
|
Ok(buf)
|
|
}
|
|
|
|
/// The energy-tiered cascade tiers (SPEC §1.1). Inherited from JouleClaw.
|
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
|
|
pub enum Tier {
|
|
/// Content-addressed cache hit (picojoules).
|
|
L0,
|
|
/// Deterministic primitive (nanojoules).
|
|
L1,
|
|
/// Embedding + hybrid retrieval (sub-millijoules).
|
|
L2,
|
|
/// Local model (joules).
|
|
L3,
|
|
/// Remote frontier agent over ACP (tens of joules); the escape hatch.
|
|
L4,
|
|
}
|
|
|
|
impl Tier {
|
|
/// The wire tag, e.g. `"L3"`.
|
|
pub fn wire_tag(self) -> &'static str {
|
|
match self {
|
|
Tier::L0 => "L0",
|
|
Tier::L1 => "L1",
|
|
Tier::L2 => "L2",
|
|
Tier::L3 => "L3",
|
|
Tier::L4 => "L4",
|
|
}
|
|
}
|
|
}
|
|
|
|
impl std::fmt::Display for Tier {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
f.write_str(self.wire_tag())
|
|
}
|
|
}
|
|
|
|
/// The one-byte algorithm identifier for signatures (SPEC §2). `0x01` =
|
|
/// Ed25519 (RFC 8032). A verifier MUST fail closed on an unknown value.
|
|
pub const ALG_ED25519: u8 = 0x01;
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn content_id_is_stable_and_prefixed() {
|
|
let a = ContentId::of_bytes(b"hello");
|
|
let b = ContentId::of_bytes(b"hello");
|
|
assert_eq!(a, b);
|
|
assert!(a.as_str().starts_with("b3:"));
|
|
}
|
|
|
|
#[test]
|
|
fn canonical_cbor_is_deterministic() {
|
|
let x = (1u8, Tier::L3, "edit");
|
|
assert_eq!(canonical_cbor(&x).unwrap(), canonical_cbor(&x).unwrap());
|
|
}
|
|
}
|