Skip to repository content
tenant.openagents/omega
No repository description is available.
OpenAgents Git authority 2026-07-28T00:57:34.490Z Public web read
NIP-34 coordinate
30617:7649603503856e5148d571eac2766b288a8ff1e9e35d380337a1d2b0015b4f92:omegaMaintainersHidden in public view
References2 branches · 1 tag
Read-only clone
git clone https://openagents.com/git/tenant.openagents/omega.gitRevision diff
9660afa6 → ae32ebd9diff --git a/crates/full_auto_ui/src/issue31_delivery.rs b/crates/full_auto_ui/src/issue31_delivery.rs
index 5514e33d16..cb39000b7a 100644
--- a/crates/full_auto_ui/src/issue31_delivery.rs
+++ b/crates/full_auto_ui/src/issue31_delivery.rs
@@ -1228,6 +1228,36 @@ mod tests {
12281228 device_public_key_hex: &str,
12291229 scopes: &[omega_effectd::Issue31PairingScope],
12301230 ) -> omega_effectd::Issue31HostController {
1231+ live_paired_controller_with_records(
1232+ host_public_key_hex,
1233+ sarah_public_key_hex,
1234+ conversation_ref,
1235+ relay_url,
1236+ device_public_key_hex,
1237+ scopes,
1238+ )
1239+ .0
1240+ }
1241+
1242+ /// The same paired controller, plus the four pairing records it is built
1243+ /// from, in the `(event id, record)` shape a device folds a grant out of.
1244+ ///
1245+ /// Nothing in the shipped host needs these: the controller holds them. A
1246+ /// *device* in another process does, because the grant is what entitles it
1247+ /// to read this host at all, and these four records were never published —
1248+ /// `record_emitted_pairing` files them, it does not put them on a relay.
1249+ /// omega#97's device half reads them out of the handoff written below.
1250+ fn live_paired_controller_with_records(
1251+ host_public_key_hex: &str,
1252+ sarah_public_key_hex: &str,
1253+ conversation_ref: &str,
1254+ relay_url: &str,
1255+ device_public_key_hex: &str,
1256+ scopes: &[omega_effectd::Issue31PairingScope],
1257+ ) -> (
1258+ omega_effectd::Issue31HostController,
1259+ Vec<(String, omega_effectd::Issue31PairingRecord)>,
1260+ ) {
12311261 use omega_effectd::{
12321262 Issue31HostConfiguration, Issue31HostController, Issue31PairingEvent,
12331263 Issue31PairingRecord,
@@ -1247,20 +1277,21 @@ mod tests {
12471277 .set_admitted_device_policy(vec![device_public_key_hex.to_string()], scopes.to_vec())
12481278 .expect("admit the device");
12491279 let now = unix_seconds();
1280+ let request = Issue31PairingRecord::PairingRequest {
1281+ schema: "openagents.omega.issue31.pairing.v1".into(),
1282+ host_ref: host_ref.clone(),
1283+ host_public_key_hex: host_public_key_hex.to_string(),
1284+ device_public_key_hex: device_public_key_hex.to_string(),
1285+ issued_at: now,
1286+ pairing_request_ref: "pairing_request.live".into(),
1287+ requested_scopes: scopes.to_vec(),
1288+ expires_at: now + 86_400,
1289+ };
12501290 let challenge = controller
12511291 .handle_pairing_event(
12521292 Issue31PairingEvent {
12531293 event_id: "a".repeat(64),
1254- record: Issue31PairingRecord::PairingRequest {
1255- schema: "openagents.omega.issue31.pairing.v1".into(),
1256- host_ref: host_ref.clone(),
1257- host_public_key_hex: host_public_key_hex.to_string(),
1258- device_public_key_hex: device_public_key_hex.to_string(),
1259- issued_at: now,
1260- pairing_request_ref: "pairing_request.live".into(),
1261- requested_scopes: scopes.to_vec(),
1262- expires_at: now + 86_400,
1263- },
1294+ record: request.clone(),
12641295 },
12651296 now,
12661297 )
@@ -1274,33 +1305,44 @@ mod tests {
12741305 panic!("expected a pairing challenge");
12751306 };
12761307 let challenge_value = challenge_value.clone();
1308+ let emitted_challenge = challenge.clone();
12771309 controller
12781310 .record_emitted_pairing("b".repeat(64), challenge)
12791311 .expect("record the challenge");
1312+ let response = Issue31PairingRecord::PairingResponse {
1313+ schema: "openagents.omega.issue31.pairing.v1".into(),
1314+ host_ref,
1315+ host_public_key_hex: host_public_key_hex.to_string(),
1316+ device_public_key_hex: device_public_key_hex.to_string(),
1317+ issued_at: now + 1,
1318+ pairing_response_ref: "pairing_response.live".into(),
1319+ pairing_challenge_event_id: "b".repeat(64),
1320+ challenge: challenge_value,
1321+ expires_at: now + 86_400,
1322+ };
12801323 let grant = controller
12811324 .handle_pairing_event(
12821325 Issue31PairingEvent {
12831326 event_id: "c".repeat(64),
1284- record: Issue31PairingRecord::PairingResponse {
1285- schema: "openagents.omega.issue31.pairing.v1".into(),
1286- host_ref,
1287- host_public_key_hex: host_public_key_hex.to_string(),
1288- device_public_key_hex: device_public_key_hex.to_string(),
1289- issued_at: now + 1,
1290- pairing_response_ref: "pairing_response.live".into(),
1291- pairing_challenge_event_id: "b".repeat(64),
1292- challenge: challenge_value,
1293- expires_at: now + 86_400,
1294- },
1327+ record: response.clone(),
12951328 },
12961329 now + 1,
12971330 )
12981331 .expect("pairing response")
12991332 .expect("scoped grant");
1333+ let emitted_grant = grant.clone();
13001334 controller
13011335 .record_emitted_pairing("d".repeat(64), grant)
13021336 .expect("record the grant");
1303- controller
1337+ (
1338+ controller,
1339+ vec![
1340+ ("a".repeat(64), request),
1341+ ("b".repeat(64), emitted_challenge),
1342+ ("c".repeat(64), response),
1343+ ("d".repeat(64), emitted_grant),
1344+ ],
1345+ )
13041346 }
13051347
13061348 #[test]
@@ -1493,9 +1535,21 @@ mod tests {
14931535 );
14941536
14951537 // Publish it, through the shipped pump, to a real paired device.
1538+ //
1539+ // `OMEGA_LIVE_DEVICE_PUBKEY` lets a device in another process — the
1540+ // openagents-mobile client, for omega#97's device half — be that
1541+ // device. It supplies only its public key: the secret never leaves the
1542+ // phone's process, so the gift wraps this host writes to the relay can
1543+ // be opened by exactly one reader, and it is not this one.
14961544 let host_keys = nostr::Keys::generate();
14971545 let sarah_keys = nostr::Keys::generate();
1498- let device_public_key_hex = nostr::Keys::generate().public_key().to_hex();
1546+ let device_public_key_hex = std::env::var("OMEGA_LIVE_DEVICE_PUBKEY")
1547+ .ok()
1548+ .map(|value| value.trim().to_ascii_lowercase())
1549+ .filter(|value| {
1550+ value.len() == 64 && value.chars().all(|byte| byte.is_ascii_hexdigit())
1551+ })
1552+ .unwrap_or_else(|| nostr::Keys::generate().public_key().to_hex());
14991553 let signer = omega_effectd::SigningIdentity::from_keys(host_keys.clone());
15001554 let owner_public_key_hex = signer.public_key_hex.clone();
15011555
@@ -1514,12 +1568,16 @@ mod tests {
15141568 Vec::new(),
15151569 )
15161570 .expect("host relay adapter");
1517- let controller = live_paired_controller(
1571+ let (controller, pairing_records) = live_paired_controller_with_records(
15181572 &owner_public_key_hex,
15191573 &sarah_keys.public_key().to_hex(),
15201574 &conversation_ref,
15211575 &relay_url,
15221576 &device_public_key_hex,
1577+ &[
1578+ omega_effectd::Issue31PairingScope::ObserveIssue31,
1579+ omega_effectd::Issue31PairingScope::ControlFullAuto,
1580+ ],
15231581 );
15241582 let grant = controller
15251583 .active_grants(unix_seconds())
@@ -1528,6 +1586,34 @@ mod tests {
15281586 .cloned()
15291587 .expect("the paired device holds an active grant");
15301588
1589+ // The handoff a device in another process needs, and nothing more: the
1590+ // host's identity and the four pairing records the grant folds out of.
1591+ // No secret and no adjunct body — the adjuncts are on the relay, which
1592+ // is the whole point of the exercise. A device that could be handed the
1593+ // reading directly would prove nothing about delivery.
1594+ if let Ok(path) = std::env::var("OMEGA_LIVE_PAIRING_OUT") {
1595+ let handoff = json!({
1596+ "relayUrl": relay_url,
1597+ "hostPublicKeyHex": owner_public_key_hex,
1598+ "sarahPublicKeyHex": sarah_keys.public_key().to_hex(),
1599+ "devicePublicKeyHex": device_public_key_hex,
1600+ "grantRef": grant.grant_ref,
1601+ "pairingRecords": pairing_records
1602+ .iter()
1603+ .map(|(event_id, record)| json!({
1604+ "canonicalRecordId": event_id,
1605+ "record": record,
1606+ }))
1607+ .collect::<Vec<_>>(),
1608+ });
1609+ std::fs::write(
1610+ &path,
1611+ serde_json::to_string_pretty(&handoff).expect("serialize the pairing handoff"),
1612+ )
1613+ .expect("write the pairing handoff");
1614+ eprintln!("omega#97: wrote the device pairing handoff to {path}");
1615+ }
1616+
15311617 let mut client =
15321618 omega_effectd::SarahConversationClient::with_relay(config, Box::new(relay), signer);
15331619 client.attach_issue31_host_controller(controller);