diff --git a/validation/src/validator.rs b/validation/src/validator.rs
index 7b4e437..f36cf73 100644
--- a/validation/src/validator.rs
+++ b/validation/src/validator.rs
@@ -21,23 +21,31 @@ fn source_has_illegal_keywords(source:&str)->bool{
 	source.find("getfenv").is_some()||source.find("require").is_some()
 }
 
+fn hash_source(source:&str)->String{
+	let mut hasher=siphasher::sip::SipHasher::new();
+	std::hash::Hasher::write(&mut hasher,source.as_bytes());
+	let hash=std::hash::Hasher::finish(&hasher);
+	format!("{:016x}",hash)
+}
+
 #[allow(dead_code)]
 #[derive(Debug)]
 pub enum ValidateError{
-	Flagged,
-	Blocked,
-	NotAllowed,
-	Get(rbx_asset::cookie::GetError),
-	ReadDom(ReadDomError),
-	ApiGetScriptPolicy(submissions_api::types::SingleItemError),
+	ScriptFlaggedIllegalKeyword,
+	ScriptBlocked(Option<submissions_api::types::ScriptID>),
+	ScriptNotYetReviewed(Option<submissions_api::types::ScriptID>),
+	ModelFileDownload(rbx_asset::cookie::GetError),
+	ModelFileDecode(ReadDomError),
+	ApiGetScriptPolicyFromHash(submissions_api::types::SingleItemError),
 	ApiGetScript(submissions_api::Error),
 	ApiCreateScript(submissions_api::Error),
 	ApiCreateScriptPolicy(submissions_api::Error),
+	ApiGetScriptFromHash(submissions_api::types::SingleItemError),
 	ApiUpdateSubmissionModel(submissions_api::Error),
 	ApiActionSubmissionValidate(submissions_api::Error),
-	WriteDom(rbx_binary::EncodeError),
-	Upload(rbx_asset::cookie::UploadError),
-	Create(rbx_asset::cookie::CreateError),
+	ModelFileEncode(rbx_binary::EncodeError),
+	AssetUpload(rbx_asset::cookie::UploadError),
+	AssetCreate(rbx_asset::cookie::CreateError),
 }
 impl std::fmt::Display for ValidateError{
 	fn fmt(&self,f:&mut std::fmt::Formatter<'_>)->std::fmt::Result{
@@ -89,10 +97,10 @@ impl Validator{
 		let data=self.roblox_cookie.get_asset(rbx_asset::cookie::GetAssetRequest{
 			asset_id:validate_info.ModelID,
 			version:Some(validate_info.ModelVersion),
-		}).await.map_err(ValidateError::Get)?;
+		}).await.map_err(ValidateError::ModelFileDownload)?;
 
 		// decode dom (slow!)
-		let mut dom=read_dom(&mut std::io::Cursor::new(data)).map_err(ValidateError::ReadDom)?;
+		let mut dom=read_dom(&mut std::io::Cursor::new(data)).map_err(ValidateError::ModelFileDecode)?;
 
 		/* VALIDATE MAP */
 
@@ -105,7 +113,7 @@ impl Validator{
 					// check the source for illegal keywords
 					if source_has_illegal_keywords(source){
 						// immediately abort
-						return Err(ValidateError::Flagged);
+						return Err(ValidateError::ScriptFlaggedIllegalKeyword);
 					}
 					// associate a name and policy with the source code
 					// policy will be fetched from the database to replace the default policy
@@ -121,14 +129,12 @@ impl Validator{
 		futures::stream::iter(script_map.iter_mut().map(Ok))
 		.try_for_each_concurrent(Some(SCRIPT_CONCURRENCY),|(source,NamePolicy{policy,name})|async{
 			// get the hash
-			let mut hasher=siphasher::sip::SipHasher::new();
-			std::hash::Hasher::write(&mut hasher,source.as_bytes());
-			let hash=std::hash::Hasher::finish(&hasher);
+			let hash=hash_source(source.as_str());
 
 			// fetch the script policy
 			let script_policy=self.api.get_script_policy_from_hash(submissions_api::types::HashRequest{
-				hash:format!("{:016x}",hash).as_str(),
-			}).await.map_err(ValidateError::ApiGetScriptPolicy)?;
+				hash:hash.as_str(),
+			}).await.map_err(ValidateError::ApiGetScriptPolicyFromHash)?;
 
 			// write the policy to the script_map, fetching the replacement code if necessary
 			if let Some(script_policy)=script_policy{
@@ -170,10 +176,22 @@ impl Validator{
 			if let Some(script)=dom.get_by_ref_mut(script_ref){
 				if let Some(rbx_dom_weak::types::Variant::String(source))=script.properties.get_mut("Source"){
 					match script_map.get(source.as_str()).map(|p|&p.policy){
-						Some(Policy::Blocked)=>return Err(ValidateError::Blocked),
+						Some(Policy::Blocked)=>{
+							let hash=hash_source(source.as_str());
+							let script=self.api.get_script_from_hash(submissions_api::types::HashRequest{
+								hash:hash.as_str(),
+							}).await.map_err(ValidateError::ApiGetScriptFromHash)?;
+							return Err(ValidateError::ScriptBlocked(script.map(|s|s.ID)));
+						},
 						None
 						|Some(Policy::None)
-						=>return Err(ValidateError::NotAllowed),
+						=>{
+							let hash=hash_source(source.as_str());
+							let script=self.api.get_script_from_hash(submissions_api::types::HashRequest{
+								hash:hash.as_str(),
+							}).await.map_err(ValidateError::ApiGetScriptFromHash)?;
+							return Err(ValidateError::ScriptNotYetReviewed(script.map(|s|s.ID)));
+						},
 						Some(Policy::Allowed)=>(),
 						Some(Policy::Delete)=>{
 							modified=true;
@@ -195,7 +213,7 @@ impl Validator{
 		if modified{
 			// serialize model (slow!)
 			let mut data=Vec::new();
-			rbx_binary::to_writer(&mut data,&dom,dom.root().children()).map_err(ValidateError::WriteDom)?;
+			rbx_binary::to_writer(&mut data,&dom,dom.root().children()).map_err(ValidateError::ModelFileEncode)?;
 
 			// upload a model lol
 			let model_id=if let Some(model_id)=validate_info.ValidatedModelID{
@@ -207,7 +225,7 @@ impl Validator{
 					ispublic:None,
 					allowComments:None,
 					groupId:None,
-				},data).await.map_err(ValidateError::Upload)?;
+				},data).await.map_err(ValidateError::AssetUpload)?;
 
 				response.AssetId
 			}else{
@@ -218,7 +236,7 @@ impl Validator{
 					ispublic:true,
 					allowComments:true,
 					groupId:None,
-				},data).await.map_err(ValidateError::Create)?;
+				},data).await.map_err(ValidateError::AssetCreate)?;
 
 				response.AssetId
 			};