open-standards/joule-code/examples/transport-moqt/tests/transport.rs
Transaction Science b3afd4e766
Some checks failed
joule-moq-remote host agent / joule-moq-remote · does this change touch it (push) Successful in 23s
joule-moq-room room service / joule-moq-room · does this change touch it (push) Successful in 28s
joule-moq-web browser client / joule-moq-web · does this change touch it (push) Successful in 28s
wai-app and Create / wai-app · does this change touch it (push) Successful in 28s
wai-fleet service / does this change touch it (push) Successful in 28s
joule-code conformance gate / joule-moq-relay, its own energy on a counter (macos) (push) Successful in 40s
joule-moq-remote host agent / joule-moq-remote, every target (macos) (push) Successful in 48s
wai-fleet service / service · macos (push) Successful in 38s
wai-app and Create / wai-app · Create, browser end-to-end (macos) (push) Successful in 5m2s
wai-app and Create / wai-app · tests, clippy, the line language's verifier (linux) (push) Successful in 38s
joule-code conformance gate / Build + round-trip C1-C4 vectors (push) Successful in 2m55s
joule-moq-web browser client / joule-moq-web · browser end-to-end (macos) (push) Successful in 17m6s
wai-fleet service / service · linux (push) Successful in 3m32s
joule-moq-remote host agent / joule-moq-remote, every target (linux-arm64) (push) Has been cancelled
joule-moq-room room service / joule-moq-room, every target (push) Has been cancelled
repository checks / lockfiles, advisories, tests in CI, workflow hygiene, spec and section references, public text (push) Has been cancelled
joule-code conformance gate / joule-moq-relay, every target (push) Has been cancelled
joule-code conformance gate / joule-moq-ingest, every target (push) Has been cancelled
The retired communicationOS name leaves the repository
communicationOS consolidated into WAI, and its site is retired. Where these texts
meant the transport they now say WAI or MoQT, and joule-moq's description, the
Joule Code docs and the Three Faces tables follow. The transport example names
joule-moq, which it uses, and its test drops the old name.

Changelog: none
Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-11-07 02:39:44 -05:00

168 lines
7.4 KiB
Rust

//! MoQT network transport for a Joule Code collaboration
//! (SPEC §7, spec/collab.md — the last federation layer).
//!
//! The full federation stack, end to end, in-process:
//!
//! BFT consensus (`LockstepCluster`) → committed, op_id-ordered coding ops
//! → published as MoQT objects over WAI's transport (`joule-moq`)
//! → each object carries a real Ed25519/BLAKE3 *signed receipt*
//! → a subscriber receives every op, verifies the signed receipts against
//! the publisher's key, and recovers the original `SignedOp` intact.
//!
//! The transport is `inv-moq` — joulesperbit's MoQT (Media over QUIC Transport)
//! wire protocol + JWP receipt extension, the WAI broadcast carrier.
//! We drive it through its `MockFabric`, which runs the real publish/subscribe/
//! receipt machinery in-process (real signatures, real BLAKE3 merkle receipts) —
//! no QUIC, no network. The `quic` feature of `inv-moq` is the real-wire path;
//! the trait surface (`Publisher` / `Subscriber` / `GroupHandle`) is identical.
use bytes::Bytes;
use ed25519_dalek::SigningKey;
use std::sync::Arc;
use joule_moq::endpoint::{Publisher, Subscriber};
use joule_moq::mock::{MockFabric, MockPublisher, MockSubscriber};
use joule_moq::receipt::ReceiptVerifier;
use joule_moq::track::{GroupId, TrackName, TrackNamespace};
use joule_code_cargo::{Anchor, CodingOp, Edit, SignedOp};
use joule_code_collab::{LockstepCluster, Membership};
use joule_code_schema::{ContentId, Tier, ALG_ED25519};
/// Build and sign a coding op against a prior state.
fn signed_op(sk: &SigningKey, prior: &str, path: &str, intent: &str) -> (SignedOp, ContentId) {
let prior = ContentId(prior.to_string());
let op = CodingOp {
alg: ALG_ED25519,
prior: prior.clone(),
edits: vec![Edit {
path: path.to_string(),
anchor: Anchor::ByteRange { start: 0, end: 0 },
replacement: intent.as_bytes().to_vec(),
}],
author: sk.verifying_key().to_bytes(),
intent: intent.to_string(),
tier: Tier::L4,
};
let signed = op.sign(sk).expect("sign op");
(signed, prior)
}
#[tokio::test]
async fn committed_ops_replicate_over_moqt_with_signed_receipts() {
// ── 1. Consensus ──────────────────────────────────────────────────────────
// A single-member BFT cluster commits two coding ops. The committed log is
// op_id-ordered and identical across every honest node; here we take that log
// as the payload stream to replicate to collaborators.
let author = SigningKey::from_bytes(&[3u8; 32]);
let membership = Membership::new(vec![author.verifying_key().to_bytes()]);
let mut cluster = LockstepCluster::new(membership, 4, []);
let (op_a, prior_a) = signed_op(&author, "b3:genesis", "src/a.rs", "fn a() {}");
let (op_b, prior_b) = signed_op(&author, "b3:genesis", "src/b.rs", "fn b() {}");
cluster.submit_round(vec![(op_a, prior_a), (op_b, prior_b)]);
let committed: Vec<SignedOp> = cluster.agreed_log().iter().map(|c| c.op.clone()).collect();
assert_eq!(committed.len(), 2, "both ops commit under honest supermajority");
// ── 2. Transport: publish committed ops over MoQT ─────────
let fabric = Arc::new(MockFabric::new());
// The publisher (this cluster endpoint) signs every object + the group root.
let endpoint_key = SigningKey::from_bytes(&[7u8; 32]);
let endpoint_vk = endpoint_key.verifying_key();
let mut publisher = MockPublisher::new(fabric.clone(), "joule-code/cluster-0", endpoint_key);
let mut subscriber = MockSubscriber::new(fabric.clone());
// Namespace/track for this collaboration's committed coding-op stream.
let ns = TrackNamespace::from_strs(["joule-code", "collab"]);
let track = TrackName::from_str("ops");
// A collaborator subscribes, requiring receipts (rejects an unsigned source).
let mut sub = subscriber
.subscribe(ns.clone(), track.clone(), true)
.await
.expect("subscribe");
publisher.announce(ns.clone()).await.expect("announce");
let mut group = publisher
.open_group(&ns, &track, GroupId(0))
.await
.expect("open group");
for op in &committed {
// Each committed op becomes one MoQT object. The `joules_micro` field is
// the transport's egress-energy meter for the object (compute energy
// lives in the op's own receipt; this is the wire cost).
let payload = Bytes::from(serde_json::to_vec(op).expect("encode op"));
group
.push_object(payload, 1_000)
.await
.expect("push object");
}
let group_receipt = group.finalize().await.expect("finalize group");
// ── 3. Receive + verify + recover ─────────────────────────────────────────
tokio::task::yield_now().await;
let mut received = Vec::new();
while let Ok(obj) = sub.rx.try_recv() {
received.push(obj);
}
assert_eq!(
received.len(),
committed.len(),
"every committed op is delivered over the transport"
);
// Verify the signed receipts against the publisher's key, then recover the op.
let verifier = ReceiptVerifier::with_anchors(vec![endpoint_vk]);
let root = verifier
.verify_group(&group_receipt)
.expect("group receipt verifies under the publisher key");
for (obj, original) in received.iter().zip(committed.iter()) {
let receipt = obj.receipt.as_ref().expect("object receipt present");
verifier
.verify_payload(&obj.payload, receipt, &root)
.expect("object receipt verifies against the group root");
let recovered: SignedOp =
serde_json::from_slice(&obj.payload).expect("recover SignedOp from payload");
assert_eq!(
&recovered, original,
"the coding op round-trips intact over the WAI transport"
);
}
}
/// A receipt-requiring subscriber must reject objects whose signed group receipt
/// does not chain to a trusted publisher key — ownerless verification, no central
/// authority deciding who is authentic.
#[tokio::test]
async fn untrusted_publisher_is_rejected() {
let fabric = Arc::new(MockFabric::new());
let attacker = SigningKey::from_bytes(&[9u8; 32]);
let trusted = SigningKey::from_bytes(&[1u8; 32]);
let mut publisher = MockPublisher::new(fabric.clone(), "imposter", attacker);
let mut subscriber = MockSubscriber::new(fabric.clone());
let ns = TrackNamespace::from_strs(["joule-code", "collab"]);
let track = TrackName::from_str("ops");
let _sub = subscriber
.subscribe(ns.clone(), track.clone(), true)
.await
.expect("subscribe");
let mut group = publisher
.open_group(&ns, &track, GroupId(0))
.await
.expect("open group");
group
.push_object(Bytes::from_static(b"forged"), 1)
.await
.expect("push");
let receipt = group.finalize().await.expect("finalize");
// The collaborator only trusts a different key; the forged group fails.
let verifier = ReceiptVerifier::with_anchors(vec![trusted.verifying_key()]);
assert!(
verifier.verify_group(&receipt).is_err(),
"an untrusted publisher's group receipt must not verify"
);
}