Skip to repository content

tenant.openagents/omega

No repository description is available.

OpenAgents Git authority 2026-07-28T00:56:18.715Z Public web read
NIP-34 coordinate30617:7649603503856e5148d571eac2766b288a8ff1e9e35d380337a1d2b0015b4f92:omega
MaintainersHidden in public view
References2 branches · 1 tag
Read-only clonegit clone https://openagents.com/git/tenant.openagents/omega.git

Revision diff

8a07c5bf c886698b
diff --git a/crates/omega_effectd/src/sarah_conversation.rs b/crates/omega_effectd/src/sarah_conversation.rs
index 38253b8534..c4c1951d34 100644
--- a/crates/omega_effectd/src/sarah_conversation.rs
+++ b/crates/omega_effectd/src/sarah_conversation.rs
@@ -6254,11 +6254,75 @@ mod tests {
62546254     /// Publish one event through a real adapter, meeting the NIP-42 challenge
62556255     /// lazily exactly as `publish_with_auth` does.
62566256     #[cfg(test)]
6257+    /// Sarah's half of the conversation, shaped the way the host actually reads it.
6258+    ///
6259+    /// The host subscribes to gift wraps addressed to its own custody key and
6260+    /// unwraps the kind-14 rumor inside into a `message` record — the identical
6261+    /// path the owner's own sends take. A bare kind 14 published straight to
6262+    /// the relay is never requested by any filter and never arrives, and a
6263+    /// kind 44300 is a `Turn`, which must carry NIP-44 ciphertext of JSON and
6264+    /// is not a conversation message at all.
6265+    ///
6266+    /// `conversation_tags` is the production tag builder, so the rumor names
6267+    /// exactly the owner and Sarah and satisfies `require_conversation_recipients`
6268+    /// rather than approximating it here.
6269+    fn sarah_conversation_wrap(
6270+        sarah_keys: &Keys,
6271+        owner_public_key: &PublicKey,
6272+        owner_public_key_hex: &str,
6273+        conversation_ref: &str,
6274+        text: &str,
6275+    ) -> nostr::Event {
6276+        let tags = conversation_tags(
6277+            conversation_ref,
6278+            owner_public_key_hex,
6279+            &sarah_keys.public_key().to_hex(),
6280+        )
6281+        .expect("production conversation tags");
6282+        let mut rumor = EventBuilder::new(Kind::PrivateDirectMessage, text)
6283+            .tags(tags)
6284+            .build(sarah_keys.public_key());
6285+        rumor.ensure_id();
6286+        smol::block_on(EventBuilder::gift_wrap(
6287+            sarah_keys,
6288+            owner_public_key,
6289+            rumor,
6290+            [],
6291+        ))
6292+        .expect("gift wrap Sarah's message to the host")
6293+    }
6294+
6295+    /// Publish, and survive a relay that closed an idle socket.
6296+    ///
6297+    /// The harness holds one Sarah connection for the life of the run and used
6298+    /// to publish straight down it. A reply sent minutes after seeding arrived
6299+    /// on a socket the relay had already reset, and the harness reported it as
6300+    /// Sarah failing to answer — indistinguishable, from the outside, from the
6301+    /// host never producing a reply. A one-message proof would have failed on
6302+    /// transport before reaching any of the record contracts.
62576303     fn device_proof_publish(
62586304         relay: &mut crate::nostr_websocket_relay::WebSocketRelayAdapter,
62596305         auth_url: &str,
62606306         keys: &Keys,
62616307         record: &Event,
6308+    ) -> Result<(), SarahConversationError> {
6309+        match device_proof_publish_authenticated(relay, auth_url, keys, record) {
6310+            Ok(()) => Ok(()),
6311+            Err(error) => {
6312+                eprintln!("device-proof: sarah publish failed ({error}); reconnecting");
6313+                relay.connect()?;
6314+                // A new socket is a new NIP-42 session, so the auth path runs
6315+                // again rather than assuming the old challenge still holds.
6316+                device_proof_publish_authenticated(relay, auth_url, keys, record)
6317+            }
6318+        }
6319+    }
6320+
6321+    fn device_proof_publish_authenticated(
6322+        relay: &mut crate::nostr_websocket_relay::WebSocketRelayAdapter,
6323+        auth_url: &str,
6324+        keys: &Keys,
6325+        record: &Event,
62626326     ) -> Result<(), SarahConversationError> {
62636327         match relay.publish(record) {
62646328             Err(SarahConversationError::IdentityRequired) => {
@@ -6436,6 +6500,7 @@ mod tests {
64366500 
64376501         let signer = SigningIdentity::from_keys(host_keys.clone());
64386502         let owner_public_key_hex = signer.public_key_hex.clone();
6503+        let owner_public_key = PublicKey::from_hex(&owner_public_key_hex).expect("owner key");
64396504         let sarah_public_key_hex = sarah_keys.public_key().to_hex();
64406505         let mut config = SarahConversationConfig::mock_fixture();
64416506         config.identity.owner_public_key_hex = owner_public_key_hex.clone();
@@ -6467,26 +6532,31 @@ mod tests {
64676532         if seed {
64686533             let sarah_relay = sarah_publisher.as_mut().expect("sarah adapter");
64696534             let now = unix_now();
6470-            let greeting = EventBuilder::new(
6471-                Kind::Custom(SARAH_TURN_RECORD_KIND),
6535+            let greeting = sarah_conversation_wrap(
6536+                &sarah_keys,
6537+                &owner_public_key,
6538+                &owner_public_key_hex,
6539+                &conversation_ref,
64726540                 "Sarah here. This reply crossed a real relay from a real Omega host.",
6473-            )
6474-            .tag(Tag::parse(["conversation", conversation_ref.as_str()]).expect("conversation tag"))
6475-            .custom_created_at(nostr::Timestamp::from(now))
6476-            .sign_with_keys(&sarah_keys)
6477-            .expect("signed Sarah message");
6541+            );
64786542             device_proof_publish(sarah_relay, &auth_url, &sarah_keys, &greeting)
64796543                 .expect("publish the Sarah greeting");
64806544             eprintln!("device-proof: seeded Sarah message {}", greeting.id.to_hex());
64816545 
64826546             // One encrypted engram, so "inspect memory" has a real source.
6483-            let owner_public_key = PublicKey::from_hex(&owner_public_key_hex).expect("owner key");
6484-            let engram_plaintext =
6485-                "Chris prefers evidence-bound reports over confident summaries.";
6547+            // An engram body is a JSON object with a `mem/…` slug and a value,
6548+            // not a sentence. Seeded as prose, the host received it, refused
6549+            // the body, and quarantined it — so "inspect memory" had no real
6550+            // source and the quarantine count was measuring this bug.
6551+            let engram_plaintext = serde_json::json!({
6552+                "slug": "mem/owner_reporting_preference",
6553+                "value": "Chris prefers evidence-bound reports over confident summaries.",
6554+            })
6555+            .to_string();
64866556             let engram_ciphertext = nip44::encrypt(
64876557                 sarah_keys.secret_key(),
64886558                 &owner_public_key,
6489-                engram_plaintext,
6559+                engram_plaintext.as_str(),
64906560                 nip44::Version::default(),
64916561             )
64926562             .expect("nip44 encrypt the engram");
@@ -6607,25 +6677,22 @@ mod tests {
66076677                     // admitted OpenAgents turn service: it produces a real
66086678                     // signed Sarah record on a real relay, and is not evidence
66096679                     // that the turn service produced it.
6610-                    // A Sarah turn is kind 44300. This harness published kind
6611-                    // 14 — a bare NIP-17 rumor — which the host never
6612-                    // subscribes to and would refuse anyway, so every reply it
6613-                    // ever "sent" was discarded in transit and the reply arm of
6614-                    // this proof had never actually run.
6615-                    let reply = EventBuilder::new(
6616-                        Kind::Custom(SARAH_TURN_RECORD_KIND),
6617-                        format!(
6680+                    // A conversation message reaches the host the same way the
6681+                    // owner's own does: a NIP-59 gift wrap addressed to the
6682+                    // host's custody key, carrying a kind-14 rumor. This
6683+                    // harness published a bare kind 14 straight to the relay,
6684+                    // which the host never subscribes to, so every reply it
6685+                    // reported sending was discarded in transit and the reply
6686+                    // arm of this proof had never once run.
6687+                    let reply = sarah_conversation_wrap(
6688+                        &sarah_keys,
6689+                        &owner_public_key,
6690+                        &owner_public_key_hex,
6691+                        &conversation_ref,
6692+                        &format!(
66186693                             "Received. Answering {turn_ref} from a real Omega host over a real relay."
66196694                         ),
6620-                    )
6621-                    .tag(
6622-                        Tag::parse(["conversation", conversation_ref.as_str()])
6623-                            .expect("conversation tag"),
6624-                    )
6625-                    .tag(Tag::parse(["turn", turn_ref.as_str()]).expect("turn tag"))
6626-                    .custom_created_at(nostr::Timestamp::from(unix_now()))
6627-                    .sign_with_keys(&sarah_keys)
6628-                    .expect("signed Sarah reply");
6695+                    );
66296696                     match device_proof_publish(sarah_relay, &auth_url, &sarah_keys, &reply) {
66306697                         Ok(()) => eprintln!(
66316698                             "device-proof: SARAH REPLIED {} · {turn_ref}",
Served at tenant.openagents/omega Member data and write actions are omitted.