From 49e01467ae38c30246080a485705eea329545ae5 Mon Sep 17 00:00:00 2001
From: Zeek <zkringlwe@gmail.com>
Date: Fri, 11 Oct 2024 02:58:33 -0400
Subject: [PATCH] migrate v1

---
 Cargo.lock                                    | 122 ++++++
 Cargo.toml                                    |  10 +-
 crates/mews_types/src/lib.rs                  |   6 +
 dnas/mewsfeed/workdir/dna.yaml                |   9 +
 .../zomes/coordinator/follows/Cargo.toml      |   7 +-
 .../follows/src/follower_to_creators.rs       | 159 ++++---
 .../zomes/coordinator/mews/Cargo.toml         |   1 +
 .../zomes/coordinator/mews/src/all_mews.rs    | 129 ++++++
 .../coordinator/mews/src/hashtag_to_mews.rs   | 116 ++++-
 .../coordinator/mews/src/mew_with_context.rs  | 146 +++++--
 .../zomes/coordinator/trust_atom/Cargo.toml   |  16 +
 .../zomes/coordinator/trust_atom/src/lib.rs   |   1 +
 .../trust_atom/tests/trust_atom_tests.rs      | 400 ++++++++++++++++++
 .../zomes/integrity/mews/src/all_mews.rs      |   6 +
 dnas/mewsfeed/zomes/integrity/mews/src/lib.rs |   9 +-
 .../integrity/trust_atom_integrity/Cargo.toml |  15 +
 .../integrity/trust_atom_integrity/src/lib.rs |   1 +
 17 files changed, 1029 insertions(+), 124 deletions(-)
 create mode 100644 dnas/mewsfeed/zomes/coordinator/trust_atom/Cargo.toml
 create mode 100644 dnas/mewsfeed/zomes/coordinator/trust_atom/src/lib.rs
 create mode 100644 dnas/mewsfeed/zomes/coordinator/trust_atom/tests/trust_atom_tests.rs
 create mode 100644 dnas/mewsfeed/zomes/integrity/trust_atom_integrity/Cargo.toml
 create mode 100644 dnas/mewsfeed/zomes/integrity/trust_atom_integrity/src/lib.rs

diff --git a/Cargo.lock b/Cargo.lock
index dad39c06..d4843ea5 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -188,6 +188,30 @@ dependencies = [
  "generic-array",
 ]
 
+[[package]]
+name = "borsh"
+version = "1.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a6362ed55def622cddc70a4746a68554d7b687713770de539e59a739b249f8ed"
+dependencies = [
+ "borsh-derive",
+ "cfg_aliases",
+]
+
+[[package]]
+name = "borsh-derive"
+version = "1.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c3ef8005764f53cd4dca619f5bf64cafd4664dada50ece25e4d81de54c80cc0b"
+dependencies = [
+ "once_cell",
+ "proc-macro-crate",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.75",
+ "syn_derive",
+]
+
 [[package]]
 name = "bumpalo"
 version = "3.16.0"
@@ -287,6 +311,12 @@ version = "1.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
 
+[[package]]
+name = "cfg_aliases"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
+
 [[package]]
 name = "chrono"
 version = "0.4.38"
@@ -796,9 +826,12 @@ version = "0.0.1"
 dependencies = [
  "follows_integrity",
  "follows_types",
+ "hc_call_utils",
  "hc_link_pagination",
  "hdk",
+ "mews_types",
  "serde",
+ "trust_atom_types",
 ]
 
 [[package]]
@@ -1730,6 +1763,15 @@ dependencies = [
  "zerocopy",
 ]
 
+[[package]]
+name = "proc-macro-crate"
+version = "3.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8ecf48c7ca261d60b74ab1a7b20da18bede46776b2e55535cb958eb595c5fa7b"
+dependencies = [
+ "toml_edit",
+]
+
 [[package]]
 name = "proc-macro-error"
 version = "1.0.4"
@@ -1990,6 +2032,22 @@ dependencies = [
  "serde",
 ]
 
+[[package]]
+name = "rust_decimal"
+version = "1.36.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b082d80e3e3cc52b2ed634388d436fe1f4de6af5786cc2de9ba9737527bdf555"
+dependencies = [
+ "arrayvec",
+ "borsh",
+ "bytes",
+ "num-traits",
+ "rand",
+ "rkyv",
+ "serde",
+ "serde_json",
+]
+
 [[package]]
 name = "rustc-demangle"
 version = "0.1.24"
@@ -2345,6 +2403,18 @@ dependencies = [
  "unicode-ident",
 ]
 
+[[package]]
+name = "syn_derive"
+version = "0.1.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1329189c02ff984e9736652b1631330da25eaa6bc639089ed4915d25446cbe7b"
+dependencies = [
+ "proc-macro-error",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.75",
+]
+
 [[package]]
 name = "tap"
 version = "1.0.1"
@@ -2558,6 +2628,58 @@ version = "1.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "683ba5022fe6dbd7133cad150478ccf51bdb6d861515181e5fc6b4323d4fa424"
 
+[[package]]
+name = "trust_atom"
+version = "0.1.32-dev"
+source = "git+https://github.com/trustgraph/trustgraph-holochain.git?branch=chore/hdk-0.3.2-using-builder#be2d3e016e7225bfceeddd381465079c956e454a"
+dependencies = [
+ "hdk",
+ "rust_decimal",
+ "serde",
+ "trust_atom_integrity",
+ "trust_atom_types",
+]
+
+[[package]]
+name = "trust_atom_integrity"
+version = "0.1.32-dev"
+source = "git+https://github.com/trustgraph/trustgraph-holochain.git?branch=chore/hdk-0.3.2-using-builder#be2d3e016e7225bfceeddd381465079c956e454a"
+dependencies = [
+ "hdi",
+ "rust_decimal",
+ "serde",
+ "trust_atom_types",
+]
+
+[[package]]
+name = "trust_atom_integrity_zome"
+version = "0.0.1"
+dependencies = [
+ "hdk",
+ "rust_decimal",
+ "serde",
+ "trust_atom_integrity",
+]
+
+[[package]]
+name = "trust_atom_types"
+version = "0.1.32-dev"
+source = "git+https://github.com/trustgraph/trustgraph-holochain.git?branch=chore/hdk-0.3.2-using-builder#be2d3e016e7225bfceeddd381465079c956e454a"
+dependencies = [
+ "hdk",
+ "serde",
+]
+
+[[package]]
+name = "trust_atom_zome"
+version = "0.0.1"
+dependencies = [
+ "hdk",
+ "rust_decimal",
+ "serde",
+ "trust_atom",
+]
+
 [[package]]
 name = "typenum"
 version = "1.17.0"
diff --git a/Cargo.toml b/Cargo.toml
index eced64bc..db347d0c 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -5,13 +5,13 @@ resolver = "2"
 [workspace.dependencies]
 hdi = "=0.4.2"
 hdk = "=0.3.2"
+# holochain_integrity_types = "=0.2.2"
 serde = "1.0"
 paste = "1.0"
 rand = "0.8.5"
 hc_prefix_index = "0.12.0"
 regex = "1.10.3"
-hc_zome_profiles_coordinator = { git = "https://github.com/holochain-open-dev/profiles.git", rev = "a1a487c8d6a8fd9910ba9b3f26e47df0bf0d09ae" }
-hc_zome_profiles_integrity = { git = "https://github.com/holochain-open-dev/profiles.git", rev = "a1a487c8d6a8fd9910ba9b3f26e47df0bf0d09ae" }
+trust_atom_types = { git = "https://github.com/trustgraph/trustgraph-holochain.git", package = "trust_atom_types", branch = "chore/hdk-0.3.2-using-builder" }
 
 [workspace.dependencies.agent_pins]
 path = "dnas/mewsfeed/zomes/coordinator/agent_pins"
@@ -57,3 +57,9 @@ path = "crates/hc_call_utils"
 
 [workspace.dependencies.hc_link_pagination]
 path = "crates/hc_link_pagination"
+
+[workspace.dependencies.trust_atom]
+path = "dnas/mewsfeed/zomes/coordinator/trust_atom"
+
+[workspace.dependencies.trust_atom_integrity]
+path = "dnas/mewsfeed/zomes/integrity/trust_atom"
\ No newline at end of file
diff --git a/crates/mews_types/src/lib.rs b/crates/mews_types/src/lib.rs
index 837a0a69..4d4feaec 100644
--- a/crates/mews_types/src/lib.rs
+++ b/crates/mews_types/src/lib.rs
@@ -2,6 +2,8 @@ use hc_link_pagination::Timestamped;
 use hdk::prelude::*;
 use std::collections::BTreeMap;
 
+pub const FOLLOW_TOPIC: &str = "__DEFAULT__";
+
 #[derive(Serialize, Deserialize, SerializedBytes, Debug, Clone, PartialEq, Eq)]
 pub enum LinkTarget {
     Mention(AgentPubKey),
@@ -42,6 +44,7 @@ pub struct Profile {
 
 #[derive(Serialize, Deserialize, SerializedBytes, Debug, Clone)]
 pub struct FeedMew {
+    // Mew with context
     pub mew: Mew,
     pub action: Action,
     pub action_hash: ActionHash,
@@ -57,6 +60,9 @@ pub struct FeedMew {
     pub is_replied: bool,
     pub is_quoted: bool,
     pub original_mew: Option<EmbedMew>,
+    // introduced with TrustAtoms
+    pub weight: Option<String>,
+    pub topic: Option<String>,
 }
 
 #[derive(Serialize, Deserialize, SerializedBytes, Debug, Clone)]
diff --git a/dnas/mewsfeed/workdir/dna.yaml b/dnas/mewsfeed/workdir/dna.yaml
index f03367da..0f893120 100644
--- a/dnas/mewsfeed/workdir/dna.yaml
+++ b/dnas/mewsfeed/workdir/dna.yaml
@@ -28,6 +28,10 @@ integrity:
       hash: ~
       bundled: "../../../target/wasm32-unknown-unknown/release/agent_pins_integrity.wasm"
       dependencies: ~
+    - name: trust_atom_integrity
+      hash: ~
+      bundled: "../../../target/wasm32-unknown-unknown/release/trust_atom_integrity_zome.wasm"
+      dependencies: ~
 coordinator:
   zomes:
     - name: profiles
@@ -60,3 +64,8 @@ coordinator:
       hash: ~
       bundled: "../../../target/wasm32-unknown-unknown/release/ping.wasm"
       dependencies: []
+    - name: trust_atom
+      hash: ~
+      bundled: "../../../target/wasm32-unknown-unknown/release/trust_atom_zome.wasm"
+      dependencies:
+        - name: trust_atom_integrity
\ No newline at end of file
diff --git a/dnas/mewsfeed/zomes/coordinator/follows/Cargo.toml b/dnas/mewsfeed/zomes/coordinator/follows/Cargo.toml
index b6942d0c..457ed52b 100644
--- a/dnas/mewsfeed/zomes/coordinator/follows/Cargo.toml
+++ b/dnas/mewsfeed/zomes/coordinator/follows/Cargo.toml
@@ -8,8 +8,11 @@ crate-type = ["cdylib", "rlib"]
 name = "follows"
 
 [dependencies]
+hc_call_utils = { workspace = true }
+hc_link_pagination = { workspace = true }
 hdk = { workspace = true }
-serde = { workspace = true }
 follows_integrity = { workspace = true } 
-hc_link_pagination = { workspace = true }
 follows_types = { workspace = true }
+mews_types ={ workspace = true}
+serde = { workspace = true }
+trust_atom_types ={ workspace = true}
\ No newline at end of file
diff --git a/dnas/mewsfeed/zomes/coordinator/follows/src/follower_to_creators.rs b/dnas/mewsfeed/zomes/coordinator/follows/src/follower_to_creators.rs
index 26bbae6a..3b785977 100644
--- a/dnas/mewsfeed/zomes/coordinator/follows/src/follower_to_creators.rs
+++ b/dnas/mewsfeed/zomes/coordinator/follows/src/follower_to_creators.rs
@@ -1,62 +1,94 @@
-use follows_integrity::*;
+use follows_integrity::LinkTypes;
+// use follows_integrity::*;
 use follows_types::*;
+use hc_call_utils::call_local_zome;
 use hc_link_pagination::paginate_by_agentpubkey;
+// use hc_link_pagination::paginate_by_agentpubkey;
 use hdk::prelude::*;
 
+use mews_types::FOLLOW_TOPIC;
+use trust_atom_types::{DeleteReport, QueryInput, TrustAtom, TrustAtomInput};
+
+#[derive(Debug, Serialize, Deserialize, SerializedBytes)]
+pub struct FollowInput {
+    pub agent: AgentPubKey,
+    pub follow_topics: Vec<FollowTopicInput>,
+}
+
+#[derive(Debug, Serialize, Deserialize, SerializedBytes)]
+pub struct FollowTopicInput {
+    pub topic: String,
+    pub weight: String,
+}
+
+#[derive(Debug, Serialize, Deserialize, SerializedBytes)]
+pub struct TrustedFeedInput {
+    pub agent: AgentPubKey,
+    pub topic: String,
+    pub weight: String,
+}
 #[hdk_extern]
 pub fn add_creator_for_follower(input: AddCreatorForFollowerInput) -> ExternResult<()> {
-    create_link(
-        input.base_follower.clone(),
-        input.target_creator.clone(),
-        LinkTypes::FollowerToCreators,
-        (),
-    )?;
-    create_link(
-        input.target_creator,
-        input.base_follower,
-        LinkTypes::CreatorToFollowers,
-        (),
-    )?;
-
-    Ok(())
+    call_local_zome(
+        "trust_atom",
+        "create_trust_atom",
+        TrustAtomInput {
+            target: AnyLinkableHash::from(input.target_creator),
+            content: Some(String::from(FOLLOW_TOPIC)),
+            value: None,
+            extra: None,
+        },
+    )
 }
 
 #[hdk_extern]
 pub fn get_creators_for_follower(
     input: GetCreatorsForFollowerInput,
 ) -> ExternResult<Vec<AgentPubKey>> {
-    let links = get_links(
-        GetLinksInputBuilder::try_new(
-            input.follower.clone(),
-            LinkTypes::FollowerToCreators.try_into_filter()?,
-        )?
-        .build(),
+    let links_from_follower_to_creators: Vec<TrustAtom> = call_local_zome(
+        "trust_atom",
+        "query",
+        QueryInput {
+            source: Some(AnyLinkableHash::from(input.follower)),
+            target: None,
+            content_full: Some(String::from(FOLLOW_TOPIC)),
+            content_starts_with: None,
+            content_not_starts_with: None,
+            value_starts_with: None,
+        },
     )?;
 
-    let links_page = paginate_by_agentpubkey(links, input.page)?;
-
-    let agents: Vec<AgentPubKey> = links_page
+    let creators: Vec<AgentPubKey> = links_from_follower_to_creators
         .into_iter()
-        .filter_map(|link| EntryHash::try_from(link.target).ok())
+        .filter_map(|link| link.target_hash.into_entry_hash())
         .map(AgentPubKey::from)
         .collect();
 
-    Ok(agents)
+    Ok(creators)
 }
 
 #[hdk_extern]
-pub fn get_followers_for_creator(
-    input: GetFollowersForCreatorInput,
-) -> ExternResult<Vec<AgentPubKey>> {
-    let links = get_follower_links_for_creator(input)?;
+pub fn get_followers_for_creator(creator: AgentPubKey) -> ExternResult<Vec<AgentPubKey>> {
+    let links_from_followers_to_creator: Vec<TrustAtom> = call_local_zome(
+        "trust_atom",
+        "query",
+        QueryInput {
+            source: None,
+            target: Some(AnyLinkableHash::from(creator)),
+            content_full: Some(String::from(FOLLOW_TOPIC)),
+            content_starts_with: None,
+            content_not_starts_with: None,
+            value_starts_with: None,
+        },
+    )?;
 
-    let agents: Vec<AgentPubKey> = links
+    let followers: Vec<AgentPubKey> = links_from_followers_to_creator
         .into_iter()
-        .filter_map(|link| EntryHash::try_from(link.target).ok())
+        .filter_map(|link| link.source_hash.into_entry_hash())
         .map(AgentPubKey::from)
         .collect();
 
-    Ok(agents)
+    Ok(followers)
 }
 
 #[hdk_extern]
@@ -107,47 +139,40 @@ pub fn get_follower_link_details_for_creator(creator: AgentPubKey) -> ExternResu
 
 #[hdk_extern]
 pub fn remove_creator_for_follower(input: RemoveCreatorForFollowerInput) -> ExternResult<()> {
-    let links = get_links(
-        GetLinksInputBuilder::try_new(
-            input.base_follower.clone(),
-            LinkTypes::FollowerToCreators.try_into_filter()?,
-        )?
-        .build(),
-    )?;
-
-    for link in links {
-        let entry_hash =
-            EntryHash::try_from(link.target.clone()).map_err(|err| wasm_error!(err))?;
-        if AgentPubKey::from(entry_hash).eq(&input.target_creator) {
-            delete_link(link.create_link_hash)?;
-        }
-    }
-
-    let links = get_links(
-        GetLinksInputBuilder::try_new(
-            input.target_creator.clone(),
-            LinkTypes::CreatorToFollowers.try_into_filter()?,
-        )?
-        .build(),
+    let _deleted_link_count: DeleteReport = call_local_zome(
+        "trust_atom",
+        "delete_trust_atoms",
+        AnyLinkableHash::from(input.target_creator),
     )?;
 
-    for link in links {
-        let entry_hash =
-            EntryHash::try_from(link.target.clone()).map_err(|err| wasm_error!(err))?;
-        if AgentPubKey::from(entry_hash).eq(&input.base_follower) {
-            delete_link(link.create_link_hash)?;
-        }
-    }
-
     Ok(())
 }
 
 #[hdk_extern]
-pub fn follow(agent: AgentPubKey) -> ExternResult<()> {
+pub fn follow(input: FollowInput) -> ExternResult<()> {
+    let agent_pubkey = agent_info()?.agent_initial_pubkey;
+    if input.agent == agent_pubkey {
+        return Err(wasm_error!("You cannot follow yourself"));
+    }
+
     add_creator_for_follower(AddCreatorForFollowerInput {
-        base_follower: agent_info()?.agent_initial_pubkey,
-        target_creator: agent,
-    })
+        base_follower: agent_pubkey,
+        target_creator: input.agent.clone(),
+    })?;
+
+    for follow_topic in input.follow_topics {
+        let _: TrustAtom = call_local_zome(
+            "trust_atom",
+            "create_trust_atom",
+            TrustAtomInput {
+                target: AnyLinkableHash::from(input.agent.clone()),
+                content: Some(follow_topic.topic),
+                value: Some(follow_topic.weight),
+                extra: None,
+            },
+        )?;
+    }
+    Ok(())
 }
 
 #[hdk_extern]
diff --git a/dnas/mewsfeed/zomes/coordinator/mews/Cargo.toml b/dnas/mewsfeed/zomes/coordinator/mews/Cargo.toml
index 2d75a308..6c423c38 100644
--- a/dnas/mewsfeed/zomes/coordinator/mews/Cargo.toml
+++ b/dnas/mewsfeed/zomes/coordinator/mews/Cargo.toml
@@ -19,3 +19,4 @@ rand = { workspace = true }
 hc_call_utils = { workspace = true }
 hc_link_pagination = { workspace = true }
 follows_types = { workspace = true }
+trust_atom = { workspace = true }
\ No newline at end of file
diff --git a/dnas/mewsfeed/zomes/coordinator/mews/src/all_mews.rs b/dnas/mewsfeed/zomes/coordinator/mews/src/all_mews.rs
index f8055249..8f244292 100644
--- a/dnas/mewsfeed/zomes/coordinator/mews/src/all_mews.rs
+++ b/dnas/mewsfeed/zomes/coordinator/mews/src/all_mews.rs
@@ -1,5 +1,19 @@
 use hdk::prelude::*;
 use mews_integrity::*;
+use crate::mew_with_context::get_batch_mews_with_context;
+
+#[hdk_extern]
+pub fn get_all_mews(_: ()) -> ExternResult<Vec<Record>> {
+    let hashes = get_all_mew_hashes()?;
+    let get_input: Vec<GetInput> = hashes
+        .into_iter()
+        .map(|hash| GetInput::new(hash.into(), GetOptions::default()))
+        .collect();
+    let records = HDK.with(|hdk| hdk.borrow().get(get_input))?;
+    let records: Vec<Record> = records.into_iter().flatten().collect();
+
+    Ok(records)
+}
 
 pub fn get_all_mew_hashes() -> ExternResult<Vec<ActionHash>> {
     let path = Path::from("all_mews");
@@ -18,3 +32,118 @@ pub fn get_all_mew_hashes() -> ExternResult<Vec<ActionHash>> {
 
     Ok(hashes)
 }
+
+#[hdk_extern]
+pub fn get_all_mews_with_context(_: ()) -> ExternResult<Vec<FeedMew>> {
+    let hashes = get_all_mew_hashes()?;
+
+    get_batch_mews_with_context(hashes)
+}
+
+// #[hdk_extern]
+// pub fn get_trusted_mews_with_context(input: RecommendedInput) -> ExternResult<Vec<FeedMew>> {
+//     let _oldest_mew_seconds = input.oldest_mew_seconds.unwrap_or(60 * 60 * 24 * 7 * 2);
+
+//     // get all TrustAtoms -- topic/author combos "rated" by this agent
+//     let trust_atoms: Vec<TrustAtom> = call_local_zome(
+//         "trust_atom",
+//         "query_mine",
+//         QueryMineInput {
+//             target: None,
+//             content_full: None,
+//             content_starts_with: None,
+//             // content_not_starts_with: Some(String::from("__")),  // TODO use this or manually filter
+//             value_starts_with: None,
+//         },
+//     )?;
+
+//     let topics_by_author: Vec<TrustAtom> = trust_atoms
+//         .into_iter()
+//         .filter(|atom| match atom.content.clone() {
+//             Some(content) => content != FOLLOW_TOPIC,
+//             None => true,
+//         })
+//         .collect();
+
+//     // debug!("topics_by_author: {:#?}", topics_by_author);
+
+//     // filter for those TrustAtoms above a weight threshold (>= 0)
+//     let recomended_topics_by_author =
+//         topics_by_author
+//             .into_iter()
+//             .filter_map(|atom| match atom.value.clone() {
+//                 Some(value_string) => {
+//                     let value_float: Result<f32, _> = value_string.parse();
+//                     match value_float {
+//                         Ok(value_float) => {
+//                             if value_float >= 0f32 {
+//                                 // let key = format!(
+//                                 //     "{}{}",
+//                                 //     atom.target_hash.clone(),
+//                                 //     atom.content.clone().unwrap_or(String::from(""))
+//                                 // );
+//                                 Some(atom)
+//                             } else {
+//                                 None
+//                             }
+//                         }
+//                         _ => None,
+//                     }
+//                 }
+//                 None => None, // null value/weight is allowed in TrustAtom lib, but not in MewsFeed
+//             });
+
+//     debug!(
+//         "recomended_topics_by_author: {:#?}",
+//         recomended_topics_by_author,
+//     );
+
+//     // get all mews by those authors
+//     let trust_feed_mews: Vec<FeedMew> = recomended_topics_by_author
+//         .flat_map(|atom| {
+//             let followed_author = atom.target_hash.clone().into_agent_pub_key();
+//             if let Some(pubkey) = followed_author {
+//                 match atom.content.clone() {
+//                     None => vec![], // TODO get all mews by this author
+//                     Some(content) => {
+//                         let feed_mews_result = get_mews_for_hashtag_by_author_with_context(
+//                             format!("#{}", content), // add # (hash) to make it a hashtag
+//                             pubkey,
+//                         );
+//                         // debug!("feed_mews_result: {:#?}", feed_mews_result);
+//                         match feed_mews_result {
+//                             Ok(feed_mews) => feed_mews
+//                                 .into_iter()
+//                                 .map(|feed_mew| FeedMew {
+//                                     weight: Some(
+//                                         atom.value
+//                                             .clone()
+//                                             .unwrap_or_else(|| String::from("0"))
+//                                             .parse::<f32>()
+//                                             .unwrap_or(0.0),
+//                                     ),
+//                                     topic: atom.content.clone(),
+//                                     ..feed_mew
+//                                 })
+//                                 .collect(),
+//                             Err(_) => vec![],
+//                         }
+//                     }
+//                 }
+//             } else {
+//                 vec![]
+//             }
+//         })
+//         .collect();
+
+//     debug!(
+//         "trust_feed_mews: {:#?}",
+//         trust_feed_mews
+//             .clone()
+//             .into_iter()
+//             .map(|feed_mew| feed_mew.clone().mew.text)
+//             .collect::<Vec<String>>()
+//     );
+
+//     Ok(trust_feed_mews)
+// }
\ No newline at end of file
diff --git a/dnas/mewsfeed/zomes/coordinator/mews/src/hashtag_to_mews.rs b/dnas/mewsfeed/zomes/coordinator/mews/src/hashtag_to_mews.rs
index e88886b0..2977b5d4 100644
--- a/dnas/mewsfeed/zomes/coordinator/mews/src/hashtag_to_mews.rs
+++ b/dnas/mewsfeed/zomes/coordinator/mews/src/hashtag_to_mews.rs
@@ -1,4 +1,4 @@
-use crate::tag_to_mews::*;
+use crate::{mew_with_context::get_mew_with_context, tag_to_mews::*};
 use hc_link_pagination::HashPagination;
 use hdk::prelude::*;
 use mews_integrity::*;
@@ -8,9 +8,22 @@ pub struct AddHashtagForMewInput {
     pub base_hashtag: String,
     pub target_mew_hash: ActionHash,
 }
+
+#[derive(Serialize, Deserialize, Debug)]
+pub struct GetMewsForHashtagWithContextInput {
+    hashtag: String,
+    page: Option<HashPagination>,
+}
+
+#[derive(Serialize, Deserialize, Debug)]
+pub struct RemoveHashtagForMewInput {
+    pub base_hashtag: String,
+    pub target_mew_hash: ActionHash,
+}
+
 #[hdk_extern]
 pub fn add_hashtag_for_mew(input: AddHashtagForMewInput) -> ExternResult<()> {
-    // Add cashtag to prefix index
+    // Add hashtag to prefix index
     let tag_text = make_tag_text(input.base_hashtag.clone());
     let prefix_index = make_tag_prefix_index()?;
     let path = prefix_index.add_result_with_label(tag_text, input.base_hashtag.clone())?;
@@ -23,14 +36,93 @@ pub fn add_hashtag_for_mew(input: AddHashtagForMewInput) -> ExternResult<()> {
         LinkTag(input.base_hashtag.as_bytes().to_vec()),
     )?;
 
+    add_hashtag_by_author_for_mew(input)?;
+
     Ok(())
 }
 
-#[derive(Serialize, Deserialize, Debug)]
-pub struct RemoveHashtagForMewInput {
-    pub base_hashtag: String,
-    pub target_mew_hash: ActionHash,
+pub fn add_hashtag_by_author_for_mew(input: AddHashtagForMewInput) -> ExternResult<()> {
+    let tag_text = make_hashtag_text(input.base_hashtag.clone());
+    let prefix_index = make_tag_prefix_index()?;
+
+    let me = agent_info()?.agent_latest_pubkey;
+    let path_text = format!("{}.{}", tag_text, me);
+    // debug!("path_text on create --- {}", path_text);
+
+    let path = prefix_index.add_result(path_text)?;
+
+    // Link from hashtag to mew_hash
+    create_link(
+        path.path_entry_hash()?,
+        input.target_mew_hash,
+        LinkTypes::HashtagByAuthorToMews,
+        LinkTag(input.base_hashtag.as_bytes().to_vec()),
+    )?;
+
+    Ok(())
 }
+
+#[hdk_extern]
+pub fn get_mews_for_hashtag_with_context(
+    input: GetMewsForHashtagWithContextInput,
+) -> ExternResult<Vec<FeedMew>> {
+    // Get links from hashtag to mew
+    let tag = make_hashtag_text(input.hashtag.clone());
+    let prefix_index = make_tag_prefix_index()?;
+    let result_path: Path = prefix_index.make_result_path(tag, Some(input.hashtag))?;
+
+    let links = get_links(
+        GetLinksInputBuilder::try_new(
+            result_path.path_entry_hash()?,
+            LinkTypes::HashtagByAuthorToMews.try_into_filter()?,
+        )?
+        .build(),
+    )?;
+
+    // Get mews with context
+    let feedmews: Vec<FeedMew> = links
+        .into_iter()
+        .filter_map(|l| l.target.into_action_hash())
+        .filter_map(|ah| get_mew_with_context(ah).ok())
+        .collect();
+
+    Ok(feedmews)
+}
+
+pub fn get_mews_for_hashtag_by_author_with_context(
+    hashtag: String,
+    agent: AgentPubKey,
+) -> ExternResult<Vec<FeedMew>> {
+    // Get links from hashtag to mew
+    let tag = make_hashtag_text(hashtag.clone());
+    let prefix_index = make_tag_prefix_index()?;
+
+    let path_text = format!("{}.{}", tag, agent);
+    // debug!("path_text --- {}", path_text);
+
+    let result_path: Path = prefix_index.make_result_path(path_text, None)?;
+
+    let links = get_links(
+        GetLinksInputBuilder::try_new(
+            result_path.path_entry_hash()?,
+            LinkTypes::HashtagByAuthorToMews.try_into_filter()?,
+        )?
+        .build(),
+    )?;
+
+    // Get mews with context
+    let feedmews: Vec<FeedMew> = links
+        .into_iter()
+        .filter_map(|l| l.target.into_action_hash())
+        .filter_map(|ah| get_mew_with_context(ah).ok())
+        .collect();
+    Ok(feedmews)
+}
+
+fn make_hashtag_text(text: String) -> String {
+    text.split('#').nth(1).unwrap_or(&text).to_string()
+}
+
 #[hdk_extern]
 pub fn remove_hashtag_for_mew(input: RemoveHashtagForMewInput) -> ExternResult<()> {
     let tag = make_tag_text(input.base_hashtag.clone());
@@ -53,15 +145,3 @@ pub fn remove_hashtag_for_mew(input: RemoveHashtagForMewInput) -> ExternResult<(
 
     Ok(())
 }
-
-#[derive(Serialize, Deserialize, Debug)]
-pub struct GetMewsForHashtagWithContextInput {
-    hashtag: String,
-    page: Option<HashPagination>,
-}
-#[hdk_extern]
-pub fn get_mews_for_hashtag_with_context(
-    input: GetMewsForHashtagWithContextInput,
-) -> ExternResult<Vec<FeedMew>> {
-    get_mews_for_tag_with_context(input.hashtag, LinkTypes::HashtagToMews, input.page)
-}
diff --git a/dnas/mewsfeed/zomes/coordinator/mews/src/mew_with_context.rs b/dnas/mewsfeed/zomes/coordinator/mews/src/mew_with_context.rs
index 5cbbee75..95792706 100644
--- a/dnas/mewsfeed/zomes/coordinator/mews/src/mew_with_context.rs
+++ b/dnas/mewsfeed/zomes/coordinator/mews/src/mew_with_context.rs
@@ -6,6 +6,119 @@ use hdk::prelude::*;
 use mews_integrity::*;
 use mews_types::Profile;
 
+fn get_agent_profile(agent_pub_key: AgentPubKey) -> ExternResult<Option<Profile>> {
+    let maybe_record = call_local_zome::<Option<Record>, AgentPubKey>(
+        "profiles",
+        "get_agent_profile",
+        agent_pub_key,
+    )?;
+
+    match maybe_record {
+        Some(record) => {
+            let profile: Profile = record
+                .entry()
+                .to_app_option()
+                .map_err(|e| wasm_error!(WasmErrorInner::Guest(e.into())))?
+                .ok_or(wasm_error!(WasmErrorInner::Guest(String::from(
+                    "Malformed Profile"
+                ))))?;
+
+            Ok(Some(profile))
+        }
+        None => Ok(None),
+    }
+}
+
+#[hdk_extern]
+pub fn get_batch_mews_with_context(hashes: Vec<ActionHash>) -> ExternResult<Vec<FeedMew>> {
+    hashes
+        .into_iter()
+        .map(get_mew_with_context)
+        .collect::<ExternResult<Vec<FeedMew>>>()
+}
+
+#[hdk_extern]
+pub fn get_batch_mews_with_context_based_on_topic_and_weight_threshold(
+    input: TrustedFeedInput,
+) -> ExternResult<Vec<FeedMew>> {
+    let topic = input.topic;
+    let min_weight = input.weight.parse::<f32>();
+
+    if let Ok(weight) = min_weight {
+        let trust_atoms_by_topic: Vec<TrustAtom> = call_local_zome(
+            "trust_atom",
+            "query",
+            QueryInput {
+                source: Some(AnyLinkableHash::from(input.agent)), // ?TODO: handle potential conversion error
+                target: None,
+                content_full: Some(topic.clone()), // query by topic
+                content_starts_with: None,
+                value_starts_with: None,
+            },
+        )?;
+
+        // debug!("trust_atoms: {:#?}", trust_atoms_by_topic.clone());
+
+        let weighted_filter: Vec<TrustAtom> = trust_atoms_by_topic
+            .clone()
+            .into_iter()
+            .filter_map(|atom| match atom.value.clone() {
+                Some(value_string) => {
+                    let value_float: Result<f32, _> = value_string.parse::<f32>(); // TODO: find way to escape iterator with an error
+                    if let Ok(value) = value_float {
+                        if value >= weight {
+                            Some(atom)
+                        } else {
+                            None
+                        }
+                    } else {
+                        None
+                    }
+                }
+                None => None,
+            })
+            .collect();
+
+        // debug!("weighted_filter: {:#?}", weighted_filter.clone());
+
+        let mut weighted_trust_feed_mews: Vec<FeedMew> = Vec::new();
+
+        for atom in weighted_filter.clone() {
+            let agent = atom.target_hash.into_agent_pub_key();
+            if let Some(pubkey) = agent {
+                let mut feed_mews =
+                    get_mews_for_hashtag_by_author_with_context(topic.clone(), pubkey)?;
+                for feed_mew in &mut feed_mews {
+                    feed_mew.topic = atom.content.clone();
+                    feed_mew.weight = atom.value.clone();
+                }
+                weighted_trust_feed_mews.append(&mut feed_mews);
+            } else {
+                return Err(wasm_error!(
+                    "error converting target hash, should be an agent pubkey"
+                ));
+            }
+        }
+
+        weighted_trust_feed_mews.sort_by(|a, b| b.weight.cmp(&a.weight));
+
+        // debug!("weighted feed: {:#?}", weighted_trust_feed_mews.clone());
+
+        debug!(
+            "trust_feed_mews: {:#?}",
+            weighted_trust_feed_mews
+                .clone()
+                .into_iter()
+                .map(|feed_mew| feed_mew.clone().mew.text)
+                .collect::<Vec<String>>()
+        );
+
+        Ok(weighted_trust_feed_mews.clone())
+    } else {
+        Err(wasm_error!("could not parse weight"))
+    }
+}
+
 #[hdk_extern]
 pub fn get_mew_with_context(original_mew_hash: ActionHash) -> ExternResult<FeedMew> {
     let response = get_details(original_mew_hash.clone(), GetOptions::default())?.ok_or(
@@ -84,6 +197,8 @@ pub fn get_mew_with_context(original_mew_hash: ActionHash) -> ExternResult<FeedM
                     is_replied,
                     is_quoted,
                     original_mew: None,
+                    weight: None, // default is None
+                    topic: None,
                 }),
                 MewType::Reply(response_to_hash)
                 | MewType::Quote(response_to_hash)
@@ -147,14 +262,6 @@ pub fn get_mew_with_context(original_mew_hash: ActionHash) -> ExternResult<FeedM
     }
 }
 
-#[hdk_extern]
-pub fn get_batch_mews_with_context(hashes: Vec<ActionHash>) -> ExternResult<Vec<FeedMew>> {
-    hashes
-        .into_iter()
-        .map(get_mew_with_context)
-        .collect::<ExternResult<Vec<FeedMew>>>()
-}
-
 #[hdk_extern]
 pub fn get_responses_for_mew_with_context(
     input: GetResponsesForMewInput,
@@ -163,26 +270,3 @@ pub fn get_responses_for_mew_with_context(
 
     get_batch_mews_with_context(response_hashes)
 }
-
-fn get_agent_profile(agent_pub_key: AgentPubKey) -> ExternResult<Option<Profile>> {
-    let maybe_record = call_local_zome::<Option<Record>, AgentPubKey>(
-        "profiles",
-        "get_agent_profile",
-        agent_pub_key,
-    )?;
-
-    match maybe_record {
-        Some(record) => {
-            let profile: Profile = record
-                .entry()
-                .to_app_option()
-                .map_err(|e| wasm_error!(WasmErrorInner::Guest(e.into())))?
-                .ok_or(wasm_error!(WasmErrorInner::Guest(String::from(
-                    "Malformed Profile"
-                ))))?;
-
-            Ok(Some(profile))
-        }
-        None => Ok(None),
-    }
-}
diff --git a/dnas/mewsfeed/zomes/coordinator/trust_atom/Cargo.toml b/dnas/mewsfeed/zomes/coordinator/trust_atom/Cargo.toml
new file mode 100644
index 00000000..c24dec12
--- /dev/null
+++ b/dnas/mewsfeed/zomes/coordinator/trust_atom/Cargo.toml
@@ -0,0 +1,16 @@
+[package]
+edition = "2021"
+name = "trust_atom_zome"
+version = "0.0.1"
+
+[lib]
+crate-type = ["cdylib", "rlib"]
+name = "trust_atom_zome"
+
+[dependencies]
+trust_atom = { git = "https://github.com/trustgraph/trustgraph-holochain.git", package = "trust_atom", branch = "chore/hdk-0.3.2-using-builder" }
+
+hdk = { workspace = true }
+serde = { workspace = true }
+rust_decimal = "1"
+
diff --git a/dnas/mewsfeed/zomes/coordinator/trust_atom/src/lib.rs b/dnas/mewsfeed/zomes/coordinator/trust_atom/src/lib.rs
new file mode 100644
index 00000000..c8ebc9f6
--- /dev/null
+++ b/dnas/mewsfeed/zomes/coordinator/trust_atom/src/lib.rs
@@ -0,0 +1 @@
+pub extern crate trust_atom;
diff --git a/dnas/mewsfeed/zomes/coordinator/trust_atom/tests/trust_atom_tests.rs b/dnas/mewsfeed/zomes/coordinator/trust_atom/tests/trust_atom_tests.rs
new file mode 100644
index 00000000..d1c78990
--- /dev/null
+++ b/dnas/mewsfeed/zomes/coordinator/trust_atom/tests/trust_atom_tests.rs
@@ -0,0 +1,400 @@
+#![warn(warnings)]
+
+use futures::future::join_all;
+use serial_test::serial;
+
+use hdk::prelude::*;
+use holochain::conductor::config::ConductorConfig;
+use holochain::sweettest::{
+    SweetAgents, SweetAppBatch, SweetCell, SweetConductor, SweetConductorBatch, SweetDnaFile,
+    SweetZome,
+};
+use holochain::test_utils::consistency_10s;
+
+use trust_atom_types::{QueryInput, TrustAtom};
+
+use follows::follower_to_creators::{FollowInput, FollowTopicInput, TrustedFeedInput};
+use mews_types::{FeedMew, Mew, MewType};
+
+const DNA_FILEPATH: &str = "../../../workdir/mewsfeed.dna";
+const MEWS_ZOME_NAME: &str = "mews";
+const FOLLOWS_ZOME_NAME: &str = "follows";
+const TRUST_ATOM_ZOME_NAME: &str = "trust_atom";
+
+// Map of Follows for convenience calculations:
+// Ann -> Bob in HC 0.5
+// Ann -> Cat in HC 1.0
+// Ann -> Dave in HC 0.25
+// Ann -> Bob in BC 0.1
+// Ann -> Cat in BC 0
+// Ann -> Dave in BC 0.55
+//
+// Feed order should be:
+// HC
+// Cat,Bob,Dave
+// BC
+// Dave,Bob (Cat excluded because of 0 value)
+
+#[tokio::test(flavor = "multi_thread")]
+#[serial]
+async fn trusted_feed_based_on_follow_topics_ordered_by_weight() {
+    let mut agent_group = setup().await;
+    let agents = agent_group.create_agents().await;
+
+    let ann = &agents[0]; // Ann is the testing agent
+    let bob = &agents[1];
+    let cat = &agents[2];
+    let dave = &agents[3];
+    // let emma = &agents[4];
+    // let frank = &agents[5];
+
+    // FOLLOWS //
+
+    // #Holochain
+
+    ann.follow(FollowInput {
+        agent: bob.pubkey.clone(),
+        follow_topics: vec![FollowTopicInput {
+            topic: String::from("holochain"),
+            weight: String::from("0.5"),
+        }],
+    })
+    .await;
+
+    ann.follow(FollowInput {
+        agent: cat.pubkey.clone(),
+        follow_topics: vec![FollowTopicInput {
+            topic: String::from("holochain"),
+            weight: String::from("1.0"),
+        }],
+    })
+    .await;
+
+    ann.follow(FollowInput {
+        agent: dave.pubkey.clone(),
+        follow_topics: vec![FollowTopicInput {
+            topic: String::from("holochain"),
+            weight: String::from("0.25"),
+        }],
+    })
+    .await;
+
+    // ann.follow(FollowInput {
+    //     agent: emma.pubkey.clone(),
+    //     follow_topics: vec![FollowTopicInput {
+    //         topic: String::from("holochain"),
+    //         weight: String::from("0.75"),
+    //     }],
+    // })
+    // .await;
+
+    // ann.follow(FollowInput {
+    //     agent: frank.pubkey.clone(),
+    //     follow_topics: vec![FollowTopicInput {
+    //         topic: String::from("holochain"),
+    //         weight: String::from("-1"), // Negative indicates spam or otherwise matierial to be thrown out
+    //     }],
+    // })
+    // .await;
+
+    // #Blockchain
+
+    ann.follow(FollowInput {
+        agent: bob.pubkey.clone(),
+        follow_topics: vec![FollowTopicInput {
+            topic: String::from("blockchain"),
+            weight: String::from("0.1"),
+        }],
+    })
+    .await;
+
+    ann.follow(FollowInput {
+        agent: cat.pubkey.clone(),
+        follow_topics: vec![FollowTopicInput {
+            topic: String::from("blockchain"),
+            weight: String::from("0"),
+        }],
+    })
+    .await;
+
+    ann.follow(FollowInput {
+        agent: dave.pubkey.clone(),
+        follow_topics: vec![FollowTopicInput {
+            topic: String::from("blockchain"),
+            weight: String::from("0.55"),
+        }],
+    })
+    .await;
+
+    // ann.follow(FollowInput {
+    //     agent: emma.pubkey.clone(),
+    //     follow_topics: vec![FollowTopicInput {
+    //         topic: String::from("blockchain"),
+    //         weight: String::from("0.33"),
+    //     }],
+    // })
+    // .await;
+
+    // ann.follow(FollowInput {
+    //     agent: frank.pubkey.clone(),
+    //     follow_topics: vec![FollowTopicInput {
+    //         topic: String::from("blockchain"),
+    //         weight: String::from("0.9"),
+    //     }],
+    // })
+    // .await;
+
+    // MEWS //
+
+    // #Holochain
+
+    bob.create_mew(Mew {
+        mew_type: MewType::Original,
+        text: String::from("#holochain from bob, weight 0.5"),
+        links: vec![],
+    })
+    .await;
+
+    cat.create_mew(Mew {
+        mew_type: MewType::Original,
+        text: String::from("#holochain from cat, weight 1.0"),
+        links: vec![],
+    })
+    .await;
+
+    dave.create_mew(Mew {
+        mew_type: MewType::Original,
+        text: String::from("#holochain from dave, weight 0.25"),
+        links: vec![],
+    })
+    .await;
+
+    // emma.create_mew(Mew {
+    //     mew_type: MewType::Original,
+    //     text: String::from("#holochain from emma, weight 0.75"),
+    //     links: vec![],
+    // })
+    // .await;
+
+    // frank
+    //     .create_mew(Mew {
+    //         mew_type: MewType::Original,
+    //         text: String::from("#holochain from frank, weight -1 should not be seen"),
+    //         links: vec![],
+    //     })
+    //     .await;
+
+    // #Blockchain
+
+    bob.create_mew(Mew {
+        mew_type: MewType::Original,
+        text: String::from("#blockchain from bob, weight 0.1"),
+        links: vec![],
+    })
+    .await;
+
+    cat.create_mew(Mew {
+        mew_type: MewType::Original,
+        text: String::from("#blockchain from cat, weight 0 should not be seen"),
+        links: vec![],
+    })
+    .await;
+
+    dave.create_mew(Mew {
+        mew_type: MewType::Original,
+        text: String::from("#blockchain from dave, weight 0.55"),
+        links: vec![],
+    })
+    .await;
+
+    // emma.create_mew(Mew {
+    //     mew_type: MewType::Original,
+    //     text: String::from("#blockchain from emma, weight 0.33"),
+    //     links: vec![],
+    // })
+    // .await;
+
+    // frank
+    //     .create_mew(Mew {
+    //         mew_type: MewType::Original,
+    //         text: String::from("#blockchain from frank, weight 0.9"),
+    //         links: vec![],
+    //     })
+    //     .await;
+
+    consistency_10s([
+        &(ann.cell.clone()),
+        &(bob.cell.clone()),
+        &(cat.cell.clone()),
+        &(dave.cell.clone()),
+        // &(emma.cell.clone()),
+        // &(frank.cell.clone()),
+    ])
+    .await;
+
+    // Show all mews on holochain topic above 0 threshold
+    let trusted_feed_holochain_topic_positive = ann
+        .trusted_feed_weighted(TrustedFeedInput {
+            agent: ann.pubkey.clone(),
+            topic: "holochain".to_string(),
+            weight: "0.000001".to_string(),
+        })
+        .await;
+
+    println!(
+        "trusted feed: {:#?}",
+        trusted_feed_holochain_topic_positive.clone()
+    );
+
+    assert!(trusted_feed_holochain_topic_positive.len() == 3);
+    assert_eq!(
+        trusted_feed_holochain_topic_positive[0].mew.text,
+        String::from("#holochain from cat, weight 1.0")
+    );
+    assert_eq!(
+        trusted_feed_holochain_topic_positive[1].mew.text,
+        String::from("#holochain from bob, weight 0.5")
+    );
+    assert_eq!(
+        trusted_feed_holochain_topic_positive[2].mew.text,
+        String::from("#holochain from dave, weight 0.25")
+    );
+
+    // Show all mews on blockchain topic above 0 threshold
+    let trusted_feed_blockchain_topic_positive = ann
+        .trusted_feed_weighted(TrustedFeedInput {
+            agent: ann.pubkey.clone(),
+            topic: "blockchain".to_string(),
+            weight: "0.000001".to_string(),
+        })
+        .await;
+
+    println!(
+        "trusted feed: {:#?}",
+        trusted_feed_blockchain_topic_positive.clone()
+    );
+
+    assert!(trusted_feed_blockchain_topic_positive.len() == 2);
+    assert_eq!(
+        trusted_feed_blockchain_topic_positive[0].mew.text,
+        String::from("#blockchain from dave, weight 0.55")
+    );
+    assert_eq!(
+        trusted_feed_blockchain_topic_positive[1].mew.text,
+        String::from("#blockchain from bob, weight 0.1")
+    );
+}
+
+//
+// ^^^ TESTS: ^^^
+//
+// vvv TEST HELPERS: vvv
+//
+
+pub struct Agent<'a> {
+    pub cell: SweetCell,
+    pub conductor: &'a SweetConductor,
+    pub pubkey: AgentPubKey,
+    pub mews_zome: SweetZome,
+    pub follows_zome: SweetZome,
+    pub trust_atom_zome: SweetZome,
+}
+
+impl Agent<'_> {
+    // pub async fn follow(&self, input: FollowInput) {
+    //     self.conductor
+    //         .call(&self.follows_zome, "follow", input)
+    //         .await
+    // }
+
+    // pub async fn create_mew(&self, input: Mew) -> ActionHash {
+    //     self.conductor
+    //         .call(&self.mews_zome, "create_mew", input)
+    //         .await
+    // }
+
+    // // pub async fn recommended(&self, input: RecommendedInput) -> Vec<FeedMew> {
+    // //     self.conductor.call(&self.zome, "recommended", input).await
+    // // }
+
+    // pub async fn trusted_feed_weighted(&self, input: TrustedFeedInput) -> Vec<FeedMew> {
+    //     self.conductor
+    //         .call(
+    //             &self.mews_zome,
+    //             "get_batch_mews_with_context_based_on_topic_and_weight_threshold",
+    //             input,
+    //         )
+    //         .await
+    // }
+}
+
+pub struct AgentGroup {
+    conductors: SweetConductorBatch,
+}
+
+impl AgentGroup {
+    #[allow(clippy::needless_lifetimes)]
+    pub async fn create_agents<'a>(&'a mut self) -> Vec<Agent<'a>> {
+        let dna_path = std::env::current_dir().unwrap().join(DNA_FILEPATH);
+        let dna = SweetDnaFile::from_bundle(&dna_path).await.unwrap();
+
+        let apps = self.conductors.setup_app("mewsfeed", &[dna]).await.unwrap();
+        self.conductors.exchange_peer_info().await;
+
+        let ((ann_cell,), (bob_cell,), (cat_cell,), (dave_cell,)) = apps.into_tuples();
+
+        let ann = Agent {
+            cell: ann_cell.clone(),
+            conductor: self.conductors.get(0).unwrap(),
+            pubkey: ann_cell.agent_pubkey().clone(),
+            mews_zome: ann_cell.zome(MEWS_ZOME_NAME),
+            follows_zome: ann_cell.zome(FOLLOWS_ZOME_NAME),
+            trust_atom_zome: ann_cell.zome(TRUST_ATOM_ZOME_NAME),
+        };
+        let bob = Agent {
+            cell: bob_cell.clone(),
+            conductor: self.conductors.get(1).unwrap(),
+            pubkey: bob_cell.agent_pubkey().clone(),
+            mews_zome: bob_cell.zome(MEWS_ZOME_NAME),
+            follows_zome: bob_cell.zome(FOLLOWS_ZOME_NAME),
+            trust_atom_zome: bob_cell.zome(TRUST_ATOM_ZOME_NAME),
+        };
+        let cat = Agent {
+            cell: cat_cell.clone(),
+            conductor: self.conductors.get(2).unwrap(),
+            pubkey: cat_cell.agent_pubkey().clone(),
+            mews_zome: cat_cell.zome(MEWS_ZOME_NAME),
+            follows_zome: cat_cell.zome(FOLLOWS_ZOME_NAME),
+            trust_atom_zome: cat_cell.zome(TRUST_ATOM_ZOME_NAME),
+        };
+        let dave = Agent {
+            cell: dave_cell.clone(),
+            conductor: self.conductors.get(3).unwrap(),
+            pubkey: dave_cell.agent_pubkey().clone(),
+            mews_zome: dave_cell.zome(MEWS_ZOME_NAME),
+            follows_zome: dave_cell.zome(FOLLOWS_ZOME_NAME),
+            trust_atom_zome: dave_cell.zome(TRUST_ATOM_ZOME_NAME),
+        };
+        // let emma = Agent {
+        //     cell: emma_cell.clone(),
+        //     conductor: self.conductors.get(4).unwrap(),
+        //     pubkey: emma_cell.agent_pubkey().clone(),
+        //     mews_zome: emma_cell.zome(MEWS_ZOME_NAME),
+        //     follows_zome: emma_cell.zome(FOLLOWS_ZOME_NAME),
+        // };
+        // let frank = Agent {
+        //     cell: frank_cell.clone(),
+        //     conductor: self.conductors.get(5).unwrap(),
+        //     pubkey: frank_cell.agent_pubkey().clone(),
+        //     mews_zome: frank_cell.zome(MEWS_ZOME_NAME),
+        //     follows_zome: frank_cell.zome(FOLLOWS_ZOME_NAME),
+        // };
+
+        vec![ann, bob, cat, dave]
+    }
+}
+
+pub async fn setup() -> AgentGroup {
+    let conductors = SweetConductorBatch::from_config(4, ConductorConfig::default()).await;
+    AgentGroup { conductors }
+}
diff --git a/dnas/mewsfeed/zomes/integrity/mews/src/all_mews.rs b/dnas/mewsfeed/zomes/integrity/mews/src/all_mews.rs
index b70fc7c0..08cee493 100644
--- a/dnas/mewsfeed/zomes/integrity/mews/src/all_mews.rs
+++ b/dnas/mewsfeed/zomes/integrity/mews/src/all_mews.rs
@@ -1,6 +1,12 @@
 use hdi::prelude::*;
 use hdk::prelude::Path;
 
+#[derive(Serialize, Deserialize, SerializedBytes, Debug, Clone)]
+pub struct RecommendedInput {
+    pub now: hdi::prelude::Timestamp,
+    pub oldest_mew_seconds: Option<u64>,
+}
+
 pub fn validate_create_link_all_mews(
     _action: CreateLink,
     base_address: AnyLinkableHash,
diff --git a/dnas/mewsfeed/zomes/integrity/mews/src/lib.rs b/dnas/mewsfeed/zomes/integrity/mews/src/lib.rs
index 4b4cd884..4e64a34a 100644
--- a/dnas/mewsfeed/zomes/integrity/mews/src/lib.rs
+++ b/dnas/mewsfeed/zomes/integrity/mews/src/lib.rs
@@ -45,6 +45,7 @@ pub enum LinkTypes {
     MewToResponses,
     MentionToMews,
     HashtagToMews,
+    HashtagByAuthorToMews,
     CashtagToMews,
 }
 
@@ -190,7 +191,7 @@ pub fn validate(op: Op) -> ExternResult<ValidateCallbackResult> {
             LinkTypes::MentionToMews => {
                 validate_create_link_mention_to_mews(action, base_address, target_address, tag)
             }
-            LinkTypes::HashtagToMews => {
+            LinkTypes::HashtagToMews | LinkTypes::HashtagByAuthorToMews => {
                 validate_create_link_hashtag_to_mews(action, base_address, target_address, tag)
             }
             LinkTypes::CashtagToMews => {
@@ -257,7 +258,7 @@ pub fn validate(op: Op) -> ExternResult<ValidateCallbackResult> {
                 target_address,
                 tag,
             ),
-            LinkTypes::HashtagToMews => validate_delete_link_hashtag_to_mews(
+            LinkTypes::HashtagToMews | LinkTypes::HashtagByAuthorToMews => validate_delete_link_hashtag_to_mews(
                 action,
                 original_action,
                 base_address,
@@ -411,7 +412,7 @@ pub fn validate(op: Op) -> ExternResult<ValidateCallbackResult> {
                 LinkTypes::MentionToMews => {
                     validate_create_link_mention_to_mews(action, base_address, target_address, tag)
                 }
-                LinkTypes::HashtagToMews => {
+                LinkTypes::HashtagToMews | LinkTypes::HashtagByAuthorToMews => {
                     validate_create_link_hashtag_to_mews(action, base_address, target_address, tag)
                 }
                 LinkTypes::CashtagToMews => {
@@ -496,7 +497,7 @@ pub fn validate(op: Op) -> ExternResult<ValidateCallbackResult> {
                         create_link.target_address,
                         create_link.tag,
                     ),
-                    LinkTypes::HashtagToMews => validate_delete_link_hashtag_to_mews(
+                    LinkTypes::HashtagToMews | LinkTypes::HashtagByAuthorToMews => validate_delete_link_hashtag_to_mews(
                         action,
                         create_link.clone(),
                         base_address,
diff --git a/dnas/mewsfeed/zomes/integrity/trust_atom_integrity/Cargo.toml b/dnas/mewsfeed/zomes/integrity/trust_atom_integrity/Cargo.toml
new file mode 100644
index 00000000..1e22d459
--- /dev/null
+++ b/dnas/mewsfeed/zomes/integrity/trust_atom_integrity/Cargo.toml
@@ -0,0 +1,15 @@
+[package]
+edition = "2021"
+name = "trust_atom_integrity_zome"
+version = "0.0.1"
+
+[lib]
+crate-type = ["cdylib", "rlib"]
+name = "trust_atom_integrity_zome"
+
+[dependencies]
+trust_atom_integrity = { git = "https://github.com/trustgraph/trustgraph-holochain.git", package = "trust_atom_integrity", branch = "chore/hdk-0.3.2-using-builder" }
+
+hdk = { workspace = true }
+serde = { workspace = true }
+rust_decimal = "1"
\ No newline at end of file
diff --git a/dnas/mewsfeed/zomes/integrity/trust_atom_integrity/src/lib.rs b/dnas/mewsfeed/zomes/integrity/trust_atom_integrity/src/lib.rs
new file mode 100644
index 00000000..c5d8cc20
--- /dev/null
+++ b/dnas/mewsfeed/zomes/integrity/trust_atom_integrity/src/lib.rs
@@ -0,0 +1 @@
+pub extern crate trust_atom_integrity;