open-standards/joule-code/joule-code-rs/crates/joule-code-joulecontract/src/lib.rs
Transaction Science 429dc59a83 joulecontract v0.8: the implementability amendment — round five seals the pack
Round five turned the adversarial method on the published artifacts
themselves: a clean-room auditor, forbidden from reading joulecontract-rs,
attempted to build a conformant validator from SPEC + conformance pack
alone. Verdict: receipt-local yes, composed no. Seventeen findings
(provenance/joulecontract-diff-v0.7-pack.md) — the bundle construction
was recoverable only by brute force, the negative vectors demanded
composed verdicts while omitting their sealed contexts, the key-log
event model showed one variant of two, the spec's literal quorum MUST
failed the golden vector, and RFC 8785 (the canonicalization any honest
implementer reaches for) produces the wrong digest.

SPEC v0.8.0 amends v0.7.0 (archived byte-exact; seven verified anchors):
bundle address = digest of LF-joined sorted member addresses; canonical
JSON defined precisely (float-ness preserved — deliberately not JCS);
DSSE PAE in the spec text; quorum scope stated (receipt-scoped k≥2 at
JR-3, per-obligation at JR-4); obligation matching exact with the frame
synthesis rule; the pack declared the normative wire form; timestamps
integer seconds; the KeyLog Added/Revoked enum on the wire.

Pack expands 13 → 22 vectors: evidence-bundle.json ships every member's
bytes (incl. the transition record), every negative embeds its sealed
context, four new mutation negatives (engagement_undisclosed,
recourse_undeclared, static_only_frame, unterminated_chain), three
context-variant vectors (timestamp_stale, breach_unamended,
verifier_revoked_window), and a JR-4 receipt making per-obligation
quorum visible. The EnB object is now sealed evidence and resolved by
the composed validator. Conformance README rewritten as an
implementer's guide; remaining unvectored behaviors stated explicitly.

Also: joule-code pre-existing clippy warnings fixed (workspace now
zero), binding emits 0.8.0.

76 joulecontract tests + 39 joule-code tests green, clippy zero on both
workspaces. Site: Round 5 card + seven-anchor chain, redeployed.

The round's lesson in the standard's own grammar: the pack was making
composed claims whose evidence was not sealed alongside — it was
running evidence:external. v0.8 seals the pack.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-06-10 16:21:44 -04:00

401 lines
16 KiB
Rust

//! A Joule Code coding operation under a JouleContract.
//!
//! The mapping is not an analogy; the objects line up field by field:
//!
//! - **The edit set is the frame.** A `CodingOp`'s `edits[].path` list is the
//! declared mutable footprint (JouleContract §3.4). An edit outside the
//! contracted paths is an out-of-frame effect — the breach primitive, made
//! concrete for code, caught at the boundary by [`frame_check`].
//! - **The tier cost is the ceiling.** The cascade's per-tier joule class
//! prices the contract's EnPI ceiling.
//! - **JCR provenance maps onto the energy classes.** `HwShunt` → `Metered`
//! (with a meter binding), `ModelBased` → `ModelBased` (with an anchor),
//! `Estimator` → `Unaccounted`. Honest in, honest out — an `Estimator`
//! figure can never serialize as `Metered` through this binding.
//!
//! The binding produces receipts that pass JouleContract's **receipt-local**
//! validation (at most JR-2 — JouleContract SPEC §10's two-stage rule);
//! composing them to JR-3+ with sealed evidence, a key log, and anchored
//! intervals is the deployment's verifier-of-record work, not this crate's.
use joule_code_cargo::CodingOp;
use joule_code_receipt::{Energy, Provenance};
use joule_code_schema::ContentId;
use joulecontract_receipt::{
DischargeEntry, DischargeResult, Engagement, FrameMode, Generator, KeyId, MeterBinding,
Qualification, Receipt, TierClass,
};
use joulecontract_schema::{
Ceiling, ContentAddress, Contract, DerivationBinding, EnergyClass, GovernanceClass, Profile,
Rigor,
};
use std::collections::BTreeSet;
/// Microjoules per joule: JCR energy records are integer µJ; JouleContract
/// ceilings are EOC joules.
const UJ_PER_J: f64 = 1_000_000.0;
/// Bridge a Joule Code content identity (`b3:…`, BLAKE3/base64) into a
/// JouleContract content address (`sha2-256:…`). The foreign identity string
/// is the addressed content — a cross-standard *reference*, not a re-hash
/// claim: resolving it back to the Joule Code object goes through the
/// original `ContentId`.
pub fn bridge_id(id: &ContentId) -> ContentAddress {
ContentAddress::of_bytes(id.0.as_bytes())
}
/// JCR provenance → JouleContract energy class. The mapping only ever moves
/// trust *down*: a coarse estimator is `Unaccounted`, never promoted.
pub fn energy_class(p: Provenance) -> EnergyClass {
match p {
Provenance::HwShunt => EnergyClass::Metered,
Provenance::ModelBased => EnergyClass::ModelBased,
Provenance::Estimator => EnergyClass::Unaccounted,
}
}
/// Build the JouleContract for a coding request: what must hold, what may be
/// touched, what may be spent.
pub fn contract_for_op(
intent: &str,
prior: &ContentId,
frame_paths: &[String],
ceiling_joules: f64,
enb_ref: ContentAddress,
derivation: Option<DerivationBinding>,
rigor_target: Rigor,
) -> Contract {
Contract {
joulecontract: "0.8.0".into(),
subject: intent.to_string(),
rigor_target,
pre: vec![format!("op builds on prior tree {}", prior.0)],
post: vec!["every edit applied within the declared frame".into()],
inv: vec![
"op signature verifies over op_id ‖ prior".into(),
"edits are ordered and pairwise disjoint".into(),
],
frame: frame_paths.to_vec(),
ceiling: Ceiling {
enpi_joules: ceiling_joules,
unit: "EOC-J".into(),
enb_ref,
derivation,
},
sector_equivalence: None,
amends: None,
}
}
#[derive(Debug, thiserror::Error, PartialEq, Eq)]
pub enum BindingError {
/// An edit outside the contracted footprint: the out-of-frame effect,
/// caught at the boundary instead of discovered in review.
#[error("out-of-frame edit: `{path}` is not within the contracted footprint")]
OutOfFrame { path: String },
#[error("contract addressing failed: {0}")]
Address(String),
}
/// Check every edit path against the contract's frame. A path is in-frame
/// when it equals a frame entry or sits under a frame entry treated as a
/// directory prefix (`src/` covers `src/lib.rs`).
pub fn frame_check(contract: &Contract, op: &CodingOp) -> Result<(), BindingError> {
for edit in &op.edits {
let in_frame = contract.frame.iter().any(|entry| {
let dir = if entry.ends_with('/') {
entry.clone()
} else {
format!("{entry}/")
};
edit.path == *entry || edit.path.starts_with(&dir)
});
if !in_frame {
return Err(BindingError::OutOfFrame {
path: edit.path.clone(),
});
}
}
Ok(())
}
/// The static identities a deployment binds once: who verifies, under what
/// qualification, paid by whom; who generates; where the meter attestation
/// comes from when the platform has one.
pub struct Binder {
pub verifier_keys: BTreeSet<KeyId>,
pub verifier_entity: Option<String>,
pub engagement: Engagement,
pub recourse: Option<String>,
pub qualification: Qualification,
pub tier_operator_keys: BTreeSet<KeyId>,
pub generator: Generator,
pub receipt_signer: KeyId,
/// Meter attestation for `HwShunt` readings (`Metered` binds or demotes).
pub meter: Option<MeterBinding>,
/// Calibration anchor for `ModelBased` readings.
pub energy_anchor: Option<ContentAddress>,
pub register_pin: ContentAddress,
/// The sealed evidence bundle address, where the deployment seals one.
pub evidence: Option<ContentAddress>,
}
impl Binder {
/// Discharge a coding operation against its contract into a JouleContract
/// receipt. The frame is checked **here** — its discharge mode is
/// `Observed` because the footprint was compared against the actual edit
/// set, not analyzed from the artifact. An out-of-frame op still gets a
/// receipt: the frame serializes `undischarged` with the offending path,
/// because a breach recorded honestly beats a breach driven underground.
pub fn receipt_for_op(
&self,
contract: &Contract,
op: &CodingOp,
op_id: &ContentId,
energy: &Energy,
) -> Result<Receipt, BindingError> {
let frame_result = match frame_check(contract, op) {
Ok(()) => DischargeResult::Closed,
Err(BindingError::OutOfFrame { path }) => DischargeResult::Undischarged {
reason: format!("out-of-frame edit: {path}"),
},
Err(e) => return Err(e),
};
let provenance = energy_class(energy.provenance);
let spent_uj = energy.measured_uj.unwrap_or(energy.estimated_uj);
let joules_spent = spent_uj as f64 / UJ_PER_J;
let binding_tier = ContentAddress::of_bytes(b"joule-code-joulecontract deterministic binding checks v1");
let discharge = contract
.obligations()
.into_iter()
.map(|ob| {
let is_frame = ob.kind == joulecontract_schema::ObligationKind::Frame;
DischargeEntry {
obligation: ob,
tier: binding_tier.clone(),
tier_class: TierClass::Deterministic,
tier_operator_keys: self.tier_operator_keys.clone(),
result: if is_frame {
frame_result.clone()
} else {
DischargeResult::Closed
},
mode: is_frame.then_some(FrameMode::Observed),
qualification: Some(self.qualification.clone()),
verifier_keys: self.verifier_keys.clone(),
verifier_entity: self.verifier_entity.clone(),
engagement: Some(self.engagement.clone()),
recourse: self.recourse.clone(),
re_discharged_by: None,
}
})
.collect();
Ok(Receipt {
contract: contract
.content_address()
.map_err(|e| BindingError::Address(e.to_string()))?,
transition: bridge_id(op_id),
generator: self.generator.clone(),
discharge,
execution: vec![ContentAddress::of_bytes(
format!("joule-code tier {:?}", op.tier).as_bytes(),
)],
joules_spent,
meter: match provenance {
EnergyClass::Metered => self.meter.clone(),
_ => None,
},
energy_anchor: match provenance {
EnergyClass::ModelBased => self.energy_anchor.clone(),
_ => None,
},
joules_allowed: contract.ceiling.enpi_joules,
provenance,
enb_ref: contract.ceiling.enb_ref.clone(),
grid_mix: None,
register_pin: self.register_pin.clone(),
evidence: self.evidence.clone(),
claimed_profile: Profile {
rigor: Rigor::Jr2,
energy: provenance,
governance: GovernanceClass::Managed,
},
receipt_signer: self.receipt_signer.clone(),
})
}
}
#[cfg(test)]
mod tests {
use super::*;
use joule_code_cargo::{Anchor, CodingOp, Edit};
use joule_code_schema::Tier;
use joulecontract_receipt::{validate, LoopGovernance, TrustRoot};
use joulecontract_schema::Demotion;
fn key(label: &str) -> KeyId {
ContentAddress::of_bytes(label.as_bytes())
}
fn op(paths: &[&str]) -> (CodingOp, ContentId) {
let op = CodingOp {
alg: 0x01,
prior: ContentId::of_bytes(b"prior tree"),
edits: paths
.iter()
.map(|p| Edit {
path: p.to_string(),
anchor: Anchor::ByteRange { start: 0, end: 4 },
replacement: b"new!".to_vec(),
})
.collect(),
author: [7u8; 32],
intent: "rename the settlement index field".into(),
tier: Tier::L1,
};
let id = ContentId::of_bytes(b"the op canonical bytes");
(op, id)
}
fn binder() -> Binder {
Binder {
verifier_keys: [key("audit-a")].into(),
verifier_entity: Some("vLEI:AUDIT-A".into()),
engagement: Engagement {
selected_by: "did:web:relying.example".into(),
compensated_by: "did:web:relying.example".into(),
},
recourse: Some("ISAE3000".into()),
qualification: Qualification {
attestation: key("binding qualification"),
signer_key: key("assessor"),
valid_until: 20_000,
validated_at: 10_000,
root: Some(TrustRoot::ReferenceImpl),
},
tier_operator_keys: [key("binding-operator")].into(),
generator: Generator {
system: "joule-code cascade".into(),
version_digest: key("cascade build"),
attestation: Some(key("cascade attestation")),
attestation_signer: Some(key("registry")),
key_set: [key("producer")].into(),
entity: Some("vLEI:PRODUCER".into()),
human_principals: vec!["did:web:eng.example".into()],
loop_governance: Some(LoopGovernance {
contract: key("loop contract"),
discharged_by: [key("audit-a")].into(),
root: TrustRoot::HumanAttested,
}),
},
receipt_signer: key("producer"),
meter: Some(MeterBinding {
attestation: key("rapl attestation"),
signer_key: key("substrate-telemetry"),
valid_until: 20_000,
validated_at: 10_000,
}),
energy_anchor: Some(key("calibration anchor")),
register_pin: key("register snapshot"),
evidence: None,
}
}
fn contract(frame: &[&str]) -> Contract {
contract_for_op(
"rename the settlement index field",
&ContentId::of_bytes(b"prior tree"),
&frame.iter().map(|s| s.to_string()).collect::<Vec<_>>(),
0.01,
key("enb"),
Some(DerivationBinding {
attestation: key("derivation"),
basis: "metered median of comparable L1 ops".into(),
signer: "did:web:energy-office.example".into(),
}),
Rigor::Jr2,
)
}
#[test]
fn in_frame_op_discharges_and_validates_to_jr2() {
let c = contract(&["src/", "Cargo.toml"]);
let (op, id) = op(&["src/lib.rs", "Cargo.toml"]);
let energy = Energy {
measured_uj: Some(1_200),
estimated_uj: 1_000,
provenance: Provenance::HwShunt,
};
let r = binder().receipt_for_op(&c, &op, &id, &energy).unwrap();
let v = validate(&c, &r).unwrap();
assert_eq!(v.max_profile.rigor, Rigor::Jr2);
assert_eq!(v.max_profile.energy, EnergyClass::Metered);
assert!(v.permits(&r.claimed_profile), "demotions: {:?}", v.demotions);
assert!((r.joules_spent - 0.0012).abs() < 1e-9);
assert!(r.residual() > 0.0);
}
#[test]
fn out_of_frame_edit_is_caught_at_the_boundary() {
let c = contract(&["src/"]);
let (op, id) = op(&["src/lib.rs", "deploy/secrets.env"]);
assert_eq!(
frame_check(&c, &op),
Err(BindingError::OutOfFrame {
path: "deploy/secrets.env".into()
})
);
// The receipt still issues — with the frame undischarged and the
// offending path on the record. Honest breach beats hidden breach.
let energy = Energy {
measured_uj: None,
estimated_uj: 900,
provenance: Provenance::ModelBased,
};
let r = binder().receipt_for_op(&c, &op, &id, &energy).unwrap();
let v = validate(&c, &r).unwrap();
assert!(v.demotions.iter().any(|d| matches!(
d,
Demotion::Undischarged { reason } if reason.contains("deploy/secrets.env")
)));
assert_eq!(v.max_profile.rigor, Rigor::Jr1, "undischarged frame caps rigor");
}
#[test]
fn estimator_energy_is_unaccounted_never_promoted() {
let c = contract(&["src/"]);
let (op, id) = op(&["src/lib.rs"]);
let energy = Energy::from_tokens(100, 10);
let r = binder().receipt_for_op(&c, &op, &id, &energy).unwrap();
assert_eq!(r.provenance, EnergyClass::Unaccounted);
assert!(r.meter.is_none(), "an estimator figure never carries a meter binding");
let v = validate(&c, &r).unwrap();
assert_eq!(v.max_profile.energy, EnergyClass::Unaccounted);
}
#[test]
fn overrun_is_recorded_not_blocked() {
// Receipt-time enforcement (JouleContract §5.3): the deviation is on
// the record as a negative residual; amend-or-fix is the resolution.
let c = contract(&["src/"]);
let (op, id) = op(&["src/lib.rs"]);
let energy = Energy {
measured_uj: Some(50_000), // 0.05 J against a 0.01 J ceiling
estimated_uj: 50_000,
provenance: Provenance::HwShunt,
};
let r = binder().receipt_for_op(&c, &op, &id, &energy).unwrap();
assert!(r.residual() < 0.0);
assert!(validate(&c, &r).is_ok(), "the system keeps running; the record decides");
}
#[test]
fn provenance_mapping_is_total_and_downward_honest() {
assert_eq!(energy_class(Provenance::HwShunt), EnergyClass::Metered);
assert_eq!(energy_class(Provenance::ModelBased), EnergyClass::ModelBased);
assert_eq!(energy_class(Provenance::Estimator), EnergyClass::Unaccounted);
}
}